home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / SamplePart (C++) / Source / SamplePart.cpp < prev    next >
Encoding:
Text File  |  1995-12-07  |  111.7 KB  |  3,455 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  
  3.     File:            SamplePart.cpp
  4.     
  5.     Written by:        Steve Smith
  6.     
  7.     Copyright:        © 1995 by Apple Computer, Inc., all rights reserved.
  8.     
  9.     Description:    SamplePart demonstrates the most basic functions and
  10.                     responsibilities of an OpenDoc™ leaf part.
  11.     
  12.     
  13.     Demonstrates:    The following recipes were used in implementing the
  14.                     SamplePart:
  15.                      1. Open
  16.                      2. Adding A Display Frame
  17.                      3. Adding A Facet
  18.                      4. Part Drawing
  19.                      5. Refcounting Geometry
  20.                      6. ViewTypes & Presentations
  21.                      7. Display Frame 'ternalization
  22.                      8. Part Init & Externalization
  23.                      9. Part Init & partWrapper
  24.                     10. Part Storage Model
  25.                     11. Persistent Reference
  26.                     12. RefCounting
  27.                     13. Storage Unit
  28.                     14. Activation
  29.                     15. Basic Event Handling
  30.                     16. Menus
  31.                     17. Windows & Dialogs
  32.                     18. Exception Handling
  33.                     19. Memory Manager
  34.                     20. Using Resources
  35.                     21. Lazy Frame Internalization
  36.                     22. Multiple Kind Support
  37.     
  38.     
  39.     Notes:            • For methods where it is necessary to call the parent class
  40.                     implementation, the calls are made from the SOM class. See
  41.                     som_SamplePart.cpp and the Class Reference to know whether
  42.                     you need to call the parent class from any method.                    
  43.     
  44. ------------------------------------------------------------------------------*/
  45.  
  46. // -- Compiler/Preprocessor Switches --
  47.  
  48. #ifndef _COMPILERDEFS_
  49. #include "CompDefs.h"
  50. #endif
  51.  
  52. // -- OpenDoc Utilities --
  53.  
  54. #ifndef _EXCEPT_
  55. // Exceptions define several important macros (eg. CHECKENV)
  56. // which are used in the SOM method dispatch glue. If Except.h
  57. // is not included early enough, exceptions may not be thrown
  58. // correctly when returning from a SOM method with the "ev" parameter set.
  59. #include <Except.h>
  60. #endif
  61.  
  62. // -- SamplePart Includes --
  63.  
  64. #ifndef _SAMPLEPARTGLOBALS_
  65. #include "SamplePartGlobals.h"
  66. #endif
  67.  
  68. #ifndef _SAMPLEPARTDEF_
  69. #include "SamplePartDef.h"
  70. #endif
  71.  
  72. #ifndef _SAMPLEPARTUTILS_
  73. #include "SamplePartUtils.h"
  74. #endif
  75.  
  76. #ifndef _SAMPLEPART_
  77. #include "SamplePart.h"
  78. #endif
  79.  
  80. #ifndef _SAMPLECOLLECTIONS_
  81. #include "SampleCollections.h"
  82. #endif
  83.  
  84. // -- OpenDoc Includes --
  85.  
  86. #ifndef _ODTYPES_
  87. #include <ODTypes.h>
  88. #endif
  89.  
  90. #ifndef SOM_ODPart_xh
  91. #include <Part.xh>
  92. #endif
  93.  
  94. #ifndef SOM_ODFacet_xh
  95. #include <Facet.xh>
  96. #endif
  97.  
  98. #ifndef SOM_ODFrame_xh
  99. #include <Frame.xh>
  100. #endif
  101.  
  102. #ifndef SOM_ODFrameFacetIterator_xh
  103. #include <FrFaItr.xh>
  104. #endif
  105.  
  106. #ifndef SOM_ODArbitrator_xh
  107. #include <Arbitrat.xh>
  108. #endif
  109.  
  110. #ifndef SOM_Module_OpenDoc_Foci_defined
  111. #include <Foci.xh>
  112. #endif
  113.  
  114. #ifndef SOM_ODShape_xh
  115. #include <Shape.xh>
  116. #endif
  117.  
  118. #ifndef SOM_Module_OpenDoc_StdProps_defined
  119. #include <StdProps.xh>
  120. #endif
  121.  
  122. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  123. #include <StdTypes.xh>
  124. #endif
  125.  
  126. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  127. #include <StdDefs.xh>
  128. #endif
  129.  
  130. #ifndef SOM_Module_OpenDoc_Commands_defined
  131. #include <CmdDefs.xh>
  132. #endif
  133.  
  134. #ifndef SOM_ODDraft_xh
  135. #include <Draft.xh>
  136. #endif
  137.  
  138. #ifndef SOM_ODStorageUnit_xh
  139. #include <StorageU.xh>
  140. #endif
  141.  
  142. #ifndef SOM_ODStorageUnitView_xh
  143. #include <SUView.xh>
  144. #endif
  145.  
  146. #ifndef SOM_ODTransform_xh
  147. #include <Trnsform.xh>
  148. #endif
  149.  
  150. #ifndef SOM_ODFocusSet_xh
  151. #include <FocusSet.xh>
  152. #endif
  153.  
  154. #ifndef SOM_ODMenuBar_xh
  155. #include <MenuBar.xh>
  156. #endif
  157.  
  158. #ifndef SOM_ODWindow_xh
  159. #include <Window.xh>
  160. #endif
  161.  
  162. #ifndef SOM_ODWindowState_xh
  163. #include <WinStat.xh>
  164. #endif
  165.  
  166. #ifndef SOM_ODCanvas_xh
  167. #include <Canvas.xh>
  168. #endif
  169.  
  170. #ifndef SOM_ODSession_xh
  171. #include <ODSessn.xh>
  172. #endif
  173.  
  174. // -- OpenDoc Utilities --
  175.  
  176. #ifndef _ITEXT_
  177. #include <IText.h>
  178. #endif
  179.  
  180. #ifndef _FOCUSLIB_
  181. #include <FocusLib.h>
  182. #endif
  183.  
  184. #ifndef _BNDNSUTL_
  185. #include <BndNSUtl.h>
  186. #endif
  187.  
  188. #ifndef _USERSRCM_
  189. #include <UseRsrcM.h>
  190. #endif
  191.  
  192. #ifndef _ODMEMORY_
  193. #include <ODMemory.h>
  194. #endif
  195.  
  196. #ifndef _ISOSTR_
  197. #include <ISOStr.h>
  198. #endif
  199.  
  200. #ifndef _ODDEBUG_
  201. #include <ODDebug.h>
  202. #endif
  203.  
  204. #ifndef _ODUTILS_
  205. #include <ODUtils.h>
  206. #endif
  207.  
  208. #ifndef _STORUTIL_
  209. #include <StorUtil.h>
  210. #endif
  211.  
  212. #ifndef _STDTYPIO_
  213. #include <StdTypIO.h>
  214. #endif
  215.  
  216. #ifndef _TEMPITER_
  217. #include <TempIter.h>
  218. #endif
  219.  
  220. #ifndef _TEMPOBJ_
  221. #include <TempObj.h>
  222. #endif
  223.  
  224. #ifndef _WINUTILS_
  225. #include <WinUtils.h>
  226. #endif
  227.  
  228. // -- Macintosh Includes --
  229.  
  230. #ifndef __ERRORS__
  231. #include <Errors.h>
  232. #endif
  233.  
  234. #ifndef __RESOURCES__
  235. #include <Resources.h>
  236. #endif
  237.  
  238. #ifndef __DIALOGS__
  239. #include <Dialogs.h>
  240. #endif
  241.  
  242. #ifndef __TOOLUTILS__
  243. #include <ToolUtils.h>
  244. #endif
  245.  
  246. #ifndef __ICONS__
  247. #include <Icons.h>
  248. #endif
  249.  
  250. #ifndef __QUICKDRAW__
  251. #include <Quickdraw.h>
  252. #endif
  253.  
  254. #ifndef __GXMATH__
  255. #include <GXMath.h>
  256. #endif
  257.  
  258. #ifndef __DRAG__
  259. #include <Drag.h>
  260. #endif
  261.  
  262. #pragma segment SamplePart
  263.  
  264. //==============================================================================
  265. // SamplePart
  266. //==============================================================================
  267.  
  268. //------------------------------------------------------------------------------
  269. // Method:        Constructor
  270. // Origin:        SamplePart
  271. //
  272. // Description:    This is the C++ class constructor.
  273. //
  274. // Warnings:    You are not allowed to throw an exception from this method.
  275. //------------------------------------------------------------------------------
  276.  
  277. SamplePart::SamplePart()
  278. {
  279.     SOM_Trace("SamplePart","Constructor");
  280.     
  281.     fDisplayFrames        = kODNULL;
  282.     fDirty                = kODFalse;
  283.     fSelf                = kODNULL;
  284.     fReadOnlyStorage    = kODFalse;
  285. }
  286.  
  287. //------------------------------------------------------------------------------
  288. // Method:        Destructor
  289. // Origin:        SamplePart
  290. //
  291. // Description:    This is the C++ class destructor.
  292. //
  293. // Warnings:    You are not allowed to throw an exception from this method.
  294. //------------------------------------------------------------------------------
  295.  
  296. SamplePart::~SamplePart()
  297. {
  298.     SOM_Trace("SamplePart","Destructor");
  299. }
  300.  
  301. //==============================================================================
  302. #pragma mark    • Initialization •
  303. //==============================================================================
  304.  
  305. //------------------------------------------------------------------------------
  306. // Method:        InitPart
  307. // Origin:        ODPart
  308. //
  309. // Description:    This method is called when a new instance of this part is being
  310. //                created. The part should prepare itself to run.
  311. //
  312. // Parent:        The part's parent class was called before this method was
  313. //                dispatched to (see som_SamplePart.cpp).
  314. //
  315. // Warning:        It is not appropriate to require user interaction while
  316. //                stationery is being created. Do not present the user with error
  317. //                dialogs or splash screens from this method.
  318. //------------------------------------------------------------------------------
  319.  
  320. void SamplePart::InitPart( Environment*        ev,
  321.                            ODStorageUnit*    storageUnit,
  322.                            ODPart*            partWrapper )
  323. {
  324.     SOM_Trace("SamplePart","InitPart");
  325.  
  326.     TRY
  327.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  328.         // that we pass in a "reference" to ourselves when interacting with the
  329.         // API (eg. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  330.         // The "partWrapper" passed to us here and in InitPartFromStorage is the
  331.         // "reference" OpenDoc is asking us to use.
  332.         fSelf = partWrapper;
  333.     
  334.         // We are being created, either as part of generating stationery or
  335.         // by some editor instantiating the part, so the destination storage
  336.         // must be writeable.
  337.         fReadOnlyStorage = kODFalse;
  338.             
  339.         // Call the common initialization code to get set up.
  340.         this->Initialize(ev);
  341.  
  342.         // Since we have just been created, our state/content info has
  343.         // never been written out, so setting our "dirty" flag will
  344.         // give us a chance to do that.
  345.         this->SetDirty(ev);
  346.     
  347.     CATCH_ALL
  348.         // Clean up will occur in the destructor which will be called
  349.         // shortly after we return the error.
  350.         RERAISE;
  351.     ENDTRY
  352. }
  353.  
  354. //------------------------------------------------------------------------------
  355. // Method:        InitPartFromStorage
  356. // Origin:        ODPart
  357. //
  358. // Description:    This method is called when a document/stationery is being opened
  359. //                or when the part is internalized by its containing part. The
  360. //                part should merely read in the saved state/content and
  361. //                initialize itself. The part must not alter its storage unit;
  362. //                otherwise, the "Save" menu item becomes enabled without the user
  363. //                actually having made a change to the document.
  364. //
  365. // Parent:        The part's parent class was called before this method was
  366. //                dispatched to (see som_SamplePart.cpp).
  367. //------------------------------------------------------------------------------
  368.  
  369. void SamplePart::InitPartFromStorage( Environment*        ev,
  370.                                       ODStorageUnit*    storageUnit,
  371.                                       ODPart*            partWrapper )
  372. {
  373.     SOM_Trace("SamplePart","InitPartFromStorage");
  374.  
  375.     TRY
  376.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  377.         // that we pass in a "reference" to ourselves when interacting with the
  378.         // API (eg. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  379.         // The "partWrapper" passed to us here and in InitPart is the
  380.         // "reference" OpenDoc is asking us to use.
  381.         fSelf = partWrapper;
  382.             
  383.         // Are we being opened from a read-only draft? If so, we cannot
  384.         // write anything back out to our storage unit.
  385.         fReadOnlyStorage = ( ODGetDraft(ev,storageUnit)->
  386.                                 GetPermissions(ev) < kODDPSharedWrite );
  387.             
  388.         // Call the common initialization code to get set up.
  389.         this->Initialize(ev);
  390.     
  391.         // Read in the state the part was in when it was last Externalized.
  392.         // This allows the part to present the same "environment" the user
  393.         // had the part set up in the last time it was edited.
  394.         this->InternalizeStateInfo(ev, storageUnit);
  395.     
  396.         // Read in the contents for your part editor.
  397.         this->InternalizeContent(ev, storageUnit);
  398.  
  399.     CATCH_ALL
  400.         // Clean up will occur in the destructor which will be called
  401.         // shortly after we return the error.
  402.         RERAISE;
  403.     ENDTRY
  404. }
  405.  
  406. //------------------------------------------------------------------------------
  407. // Method:        Initialize
  408. // Origin:        SamplePart
  409. //
  410. // Description:    This method is called during the initialization of the part. The
  411. //                method is used to initialize all fields of the part and to
  412. //                convert ISO types to tokens for faster comparisons throughout
  413. //                the code.
  414. //
  415. //                If an exception is thrown in this method, it wil be propogated
  416. //                back to OpenDoc which will call our ReleaseAll() method and the
  417. //                class destructor. All memory allocated here will be cleaned up
  418. //                in the ReleaseAll() method.
  419. //------------------------------------------------------------------------------
  420.  
  421. void SamplePart::Initialize( Environment*    ev )
  422. {
  423.     SOM_Trace("SamplePart","Initialize");
  424.  
  425.     // Create a list to keep track of the frames we are being
  426.     // displayed in. Used for part maintenance (ie. Purging memory).
  427.     fDisplayFrames = new CList;
  428.  
  429.     // First check to see if the library's global variables have
  430.     // been initialized (meaning another part instantiation is already
  431.     // running).
  432.  
  433.     if ( gGlobalsUsageCount == 0 )
  434.     {
  435.         // Grab a reference to the Session object. This is merely for
  436.         // convenience.
  437.         ODSession* session = ODGetSession(ev,fSelf);
  438.             
  439.         // Create our globals space. We store the globals in a struct so
  440.         // that we can put them in temp mem. Otherwise, CFM loads the globals
  441.         // with the data fragment of a CFM library in the application heap.
  442.         gGlobals = new SamplePartGlobals;
  443.     
  444.         // It is required that parts instantiate their menu bars from 
  445.         // the base OpenDoc menu bar. This maintains consistency in the
  446.         // default menu items and their placement.
  447.         // Since the object is a copy, we can add and subtract menus and
  448.         // items without affecting other running parts.
  449.         gGlobals->fMenuBar = session->GetWindowState(ev)->CopyBaseMenuBar(ev);
  450.  
  451.         // We will be using the following foci (shared resources) in this
  452.         // part. For convenience, we tokenize the values here and store
  453.         // them for equivalence tests in the activation methods.
  454.         gGlobals->fSelectionFocus = session->Tokenize(ev, kODSelectionFocus);
  455.         gGlobals->fMenuFocus = session->Tokenize(ev, kODMenuFocus);
  456.         gGlobals->fModalFocus = session->Tokenize(ev, kODModalFocus);
  457.     
  458.         // Also for convenience, we tokenize our part's main presentation
  459.         // and the standard view types.
  460.         gGlobals->fMainPresentation = session->Tokenize(ev, kMainPresentation);
  461.     
  462.         gGlobals->fFrameView = session->Tokenize(ev, kODViewAsFrame);
  463.         gGlobals->fLargeIconView = session->Tokenize(ev, kODViewAsLargeIcon);
  464.         gGlobals->fSmallIconView = session->Tokenize(ev, kODViewAsSmallIcon);
  465.         gGlobals->fThumbnailView = session->Tokenize(ev, kODViewAsThumbnail);
  466.     
  467.         // Lastly, we will package the menu and selection focus
  468.         // so that we can request the "set" at activation time.
  469.         gGlobals->fUIFocusSet = session->GetArbitrator(ev)->CreateFocusSet(ev);
  470.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fMenuFocus);
  471.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fSelectionFocus);
  472.             
  473.         // Determine what Script/Language the part is localized for.
  474.         // This is important/necessary for creating OpenDoc's text objects.
  475.         GetEditorScriptLanguage(ev, &gGlobals->fEditorsScript, &gGlobals->fEditorsLanguage);
  476.         
  477.         // The first client of the global variables is running.
  478.         gGlobalsUsageCount = 1;
  479.     }
  480.     else
  481.     // If the globals have been initialized, we just bump the "usage" count so
  482.     // that we know how many part instances are using them.
  483.     {
  484.         gGlobalsUsageCount++;
  485.     }
  486. }
  487.  
  488. //==============================================================================
  489. #pragma mark    • Storage •
  490. //==============================================================================
  491.  
  492. //------------------------------------------------------------------------------
  493. // Method:        Release
  494. // Origin:        ODPart
  495. //
  496. // Description:    This method is called each time an object releases a reference
  497. //                to the part. If the refcount falls to 0, the part should
  498. //                release the fSelf part reference.
  499. //
  500. // Parent:        The part's parent class was called before this method was
  501. //                dispatched to (see som_SamplePart.cpp).
  502. //
  503. // Warning:        If the part releases any other object when the refcount falls to
  504. //                zero, it will need to override the Acquire method so
  505. //                that the object can be referenced again if the parts refcount
  506. //                should be incremented before it is deleted.
  507. //------------------------------------------------------------------------------
  508.  
  509. void SamplePart::Release( Environment* ev )
  510. {
  511.     SOM_Trace("SamplePart","Release");
  512.  
  513.     if ( fSelf->GetRefCount(ev) == 0 )
  514.         ODGetDraft(ev,fSelf)->ReleasePart(ev,fSelf);
  515. }
  516.  
  517. //------------------------------------------------------------------------------
  518. // Method:        ReleaseAll
  519. // Origin:        ODPart
  520. //
  521. // Description:    This method is called just prior to the part being deleted by
  522. //                the Draft. The part must release all references to all
  523. //                refcounted objects it has stored internally; not doing so, will
  524. //                cause an "invalid ref count" exception/error at some later time.
  525. //
  526. // Parent:        The part's parent class will be called after this method
  527. //                returns (see som_SamplePart.cpp).
  528. //------------------------------------------------------------------------------
  529.  
  530. void SamplePart::ReleaseAll( Environment* ev )
  531. {
  532.     SOM_Trace("SamplePart","ReleaseAll");
  533.  
  534.     TRY
  535.         // If the last part instance using the globals is released,
  536.         // we need to clean up and delete the globals.
  537.         
  538.         if ( --gGlobalsUsageCount == 0 )
  539.         {
  540.             // Release the menubar.
  541.             ODReleaseObject(ev, gGlobals->fMenuBar);
  542.             
  543.             // But first, we need to delete the objects we created
  544.             // and stored in the globals struct.
  545.             ODDeleteObject(gGlobals->fUIFocusSet);
  546.  
  547.             // Release the thumbnail (PICT) resource.
  548.             if ( gGlobals->fThumbnail )
  549.             {
  550.                 ReleaseResource(gGlobals->fThumbnail);
  551.                 gGlobals->fThumbnail = kODNULL;
  552.             }
  553.             
  554.             // Now, clean up the globals struct.
  555.             ODDeleteObject(gGlobals);
  556.         }
  557.     
  558.         // Remove and release our display frames.
  559.         if ( fDisplayFrames )
  560.         {
  561.             CListIterator fiter(fDisplayFrames);
  562.             for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  563.                     fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  564.             {
  565.                 // Delete the proxy object and its contents. The frame's
  566.                 // refcount will be decremented in the proxy destructor.
  567.                 fiter.RemoveCurrent();
  568.                 delete proxy;
  569.             }
  570.         
  571.             // Delete the display frame collection.
  572.             ODDeleteObject(fDisplayFrames);
  573.         }
  574.         
  575.     CATCH_ALL
  576.         // If something goes wrong while we are cleaning up, we must
  577.         // let the Draft now because there may be some refcounted objects
  578.         // which did not get released. Not to mention, possible memory
  579.         // leaks.
  580.         RERAISE;            
  581.     ENDTRY
  582. }
  583.  
  584. //------------------------------------------------------------------------------
  585. // Method:        Purge
  586. // Origin:        ODPart
  587. //
  588. // Description:    This method is called when the OpenDoc requires more memory for
  589. //                allocating objects and just before a part is deleted. The part
  590. //                should free up as much memory as it can.
  591. //
  592. //                The part determines which views are being "used" in its display
  593. //                frames. The resources for the unused view types are then purged.
  594. //------------------------------------------------------------------------------
  595.  
  596. ODSize SamplePart::Purge( Environment*    ev,
  597.                           ODSize        /*size*/ )
  598. {
  599.     SOM_Trace("SamplePart","Purge");
  600.  
  601.     // Purge is called during the creation of stationery. However,
  602.     // we have not created our internal display frames list, so 
  603.     // trying to iterate over it would be fatal.
  604.     if ( fDisplayFrames == kODNULL ) return 0;
  605.     
  606.     ODSize         bytesFreed        = 0;
  607.     ODBoolean    usingThumbnail  = kODFalse;
  608.     
  609.     // Iterate over the frames we are displayed through and determine which
  610.     // view types are currently in use.
  611.     
  612.     CListIterator fiter(fDisplayFrames);
  613.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  614.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  615.     {
  616.         // If the display frame is real (has been "connected" or was "added")
  617.         // get its view type; otherwise, ignore it.
  618.         if ( proxy->FrameIsLoaded(ev) )
  619.         {
  620.             ODTypeToken    frameView = proxy->GetFrame(ev)->GetViewType(ev);
  621.             
  622.             if ( frameView == gGlobals->fThumbnailView )
  623.                 usingThumbnail = kODTrue;
  624.             
  625.             // Release the frame reference, but don't get rid of the
  626.             // proxy object because we're not done with the frame. If
  627.             // all parts release their references the frame will be
  628.             // purged from memory.
  629.             proxy->Purge(ev);
  630.         }
  631.     }
  632.     
  633.     // Based on the usage of the supported view types, free up as much
  634.     // memory as possible.
  635.  
  636.     if ( !usingThumbnail && (gGlobals->fThumbnail != kODNULL) )
  637.     {
  638.         bytesFreed += (ODSize) ODGetHandleSize(gGlobals->fThumbnail);
  639.         ReleaseResource(gGlobals->fThumbnail);
  640.         gGlobals->fThumbnail = kODNULL;
  641.     }
  642.     
  643.     return bytesFreed;
  644. }
  645.  
  646. //------------------------------------------------------------------------------
  647. // Method:        InternalizeStateInfo
  648. // Origin:        SamplePart
  649. //
  650. // Description:    This method is used to read in "state" information for the part.
  651. //                This is information related to the workings of the part editor,
  652. //                not the content.
  653. //
  654. //                The part writes out a list of weak references to its display
  655. //                frames. This allows the part to reuse the same display frames
  656. //                each time the document is opened. Those references are read
  657. //                back in and validated here.
  658. //
  659. // Note:        The function StorageUnitGetValue simplifies the use of
  660. //                ODByteArrary, which is required the StorageUnit interface. Look
  661. //                in StorUtil.h/cpp for an example of using the ODByteArray struct.
  662. //------------------------------------------------------------------------------
  663.  
  664. void SamplePart::InternalizeStateInfo( Environment*        ev,
  665.                                        ODStorageUnit*    storageUnit )
  666. {
  667.     SOM_Trace("SamplePart","InternalizeStateInfo");
  668.  
  669.     ODStorageUnitRef    weakRef;
  670.     ODULong                size;
  671.  
  672.     // Internalize the part's display frame list.
  673.  
  674.     if ( storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  675.     {
  676.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  677.                                     kODWeakStorageUnitRefs, 0, kODPosUndefined);
  678.                                     
  679.         size = storageUnit->GetSize(ev);
  680.         storageUnit->SetOffset(ev, 0);    
  681.     
  682.         for ( ODULong offset = 0; offset < size; offset += kODStorageUnitRefSize )
  683.         {    
  684.             TRY    
  685.                 StorageUnitGetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  686.                 
  687.                 if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) )
  688.                 {        
  689.                     // We lazily internalize our display frames, meaning we don't "get"
  690.                     // the frame until we absolutely need it. This reduces the time
  691.                     // to internalize the part and the amount of memory needed.
  692.                     
  693.                     // Convert the reference into a runtime id.
  694.                     ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef);
  695.  
  696.                     // Create a proxy class to support the lazy internalization.
  697.                     CFrameProxy* proxy = new CFrameProxy;
  698.                     proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit));
  699.  
  700.                     // Add the proxy to the display frame collection.
  701.                     fDisplayFrames->Add(proxy);
  702.                 }
  703.             CATCH_ALL
  704.                 // consume exception
  705.             ENDTRY
  706.         }
  707.     }
  708. }
  709.  
  710. //------------------------------------------------------------------------------
  711. // Method:        InternalizeContent
  712. // Origin:        SamplePart
  713. //
  714. // Description:    This method is called during initialization of the part from an
  715. //                existing document. The content of the part should be read in.
  716. //
  717. //                The part has no intrinsic content, so the part does nothing.
  718. //                The method is here for completeness.
  719. //------------------------------------------------------------------------------
  720.  
  721. void SamplePart::InternalizeContent( Environment*        ev,
  722.                                      ODStorageUnit*        /*storageUnit*/ )
  723. {
  724.     SOM_Trace("SamplePart","InternalizeContent");
  725.     
  726. }
  727.  
  728. //------------------------------------------------------------------------------
  729. // Method:        CloneInto
  730. // Origin:        ODPart
  731. //
  732. // Description:    This method is called during cloning, typically during data
  733. //                interchange operations (eg. Cut/Paste). The part should
  734. //                write out its current state and content.
  735. //
  736. // Parent:        The part's parent class was called before this method was
  737. //                dispatched to (see som_SamplePart.cpp).
  738. //------------------------------------------------------------------------------
  739.  
  740. void SamplePart::CloneInto( Environment*        ev,
  741.                             ODDraftKey            key,
  742.                             ODStorageUnit*        destinationSU,
  743.                             ODFrame*            initiatingFrame )
  744. {
  745.     SOM_Trace("SamplePart","CloneInto");
  746.     
  747.     // We must first verify that we've never written to this storage unit.
  748.     // If we have, we should do nothing, otherwise we need to write out
  749.     // the current state of the part content.
  750.     
  751.     if ( destinationSU->Exists(ev, kODPropContents, kSamplePartKind, 0) == kODFalse )
  752.     {
  753.         // Add the properties we need to successfully externalize
  754.         // ourselves into the destination storage unit.
  755.         this->CheckAndAddProperties(ev, destinationSU);
  756.                 
  757.         // Write out the part's state information.
  758.         this->ExternalizeStateInfo(ev, destinationSU, key, initiatingFrame);
  759.             
  760.         // Write out the part's content.
  761.         this->ExternalizeContent(ev, destinationSU, key, initiatingFrame);
  762.     }
  763. }
  764.  
  765. //------------------------------------------------------------------------------
  766. // Method:        Externalize
  767. // Origin:        ODPart
  768. //
  769. // Description:    This method is called when the user saves the document. The part
  770. //                should write out its state and content if changes have occurred
  771. //                and if our storage is writeable.
  772. //
  773. // Parent:        The part's parent class was called before this method was
  774. //                dispatched to (see som_SamplePart.cpp).
  775. //------------------------------------------------------------------------------
  776.  
  777. void SamplePart::Externalize( Environment* ev )
  778. {
  779.     SOM_Trace("SamplePart","Externalize");
  780.  
  781.     TRY
  782.         if ( fDirty && !fReadOnlyStorage )
  783.         {
  784.             // Get our storage unit.
  785.             ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  786.         
  787.             // Verify that the storage unit has the appropriate properties
  788.             // and values to allow us to run. If not, add them.
  789.             this->CheckAndAddProperties(ev, storageUnit);
  790.         
  791.             // Verify that there are no "bogus" values in the Content
  792.             // property.
  793.             this->CleanseContentProperty(ev, storageUnit);
  794.         
  795.             // Write out the part's state information.
  796.             this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  797.                 
  798.             // Write out the part's content.
  799.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  800.     
  801.             // Flag our part as no longer being dirty.
  802.             fDirty = kODFalse;
  803.         }
  804.     CATCH_ALL
  805.         // Alert the user of the problem.
  806.         this->DoDialogBox(ev, kODNULL, kErrorBoxID, kErrExternalizeFailed);
  807.         // Change the exception value, so the DocShell doesn't display an
  808.         // error dialog.
  809.         SetErrorCode(kODErrAlreadyNotified);
  810.         // Alert the caller.
  811.         RERAISE;
  812.     ENDTRY
  813. }
  814.  
  815. //------------------------------------------------------------------------------
  816. // Method:        ExternalizeKinds
  817. // Origin:        ODPart
  818. //
  819. // Description:    This method is called when the user wants to save the document
  820. //                with multiple representations of the data. This is especially
  821. //                useful for increasing the portability of documents
  822. //                cross-platform.
  823. //
  824. //                A part should verify each kind is valid, that it exists in
  825. //                the content property in the correct order, and write the data.
  826. //
  827. // Note:        For parts which support only on kind, the code can simplified.
  828. //                In this case, it is not necessary to iterate over the kindset
  829. //                because you must, at least, write your preferred kind. The code
  830. //                is shown this way to better illustrate the recipe; it is not
  831. //                wrong, it just does more than it needs to.
  832. //------------------------------------------------------------------------------
  833.  
  834. void SamplePart::ExternalizeKinds( Environment*        ev,
  835.                                    ODTypeList*        kindset )
  836. {
  837.     if ( !fReadOnlyStorage )
  838.     {
  839.         ODBoolean preferredKindWritten = kODFalse;
  840.         
  841.         // Get our storage unit.
  842.         ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  843.         
  844.         // Verify that the storage unit has the appropriate properties
  845.         // and values to allow us to run. If not, add them.
  846.         this->CheckAndAddProperties(ev, storageUnit);
  847.     
  848.         // Verify that there are no "bogus" values in the Content
  849.         // property.
  850.         this->CleanseContentProperty(ev, storageUnit);
  851.     
  852.         // Iterate over the kindset and write out the content types
  853.         // that we support.
  854.         TempODTypeListIterator tliter(ev, kindset);
  855.         for ( ODType kind = tliter.First(); tliter.IsNotComplete();
  856.                 kind = tliter.Next() )
  857.         {
  858.             // Check to see if this is a kind we support. If so, write it.
  859.             if ( ODISOStrCompare(kind, kSamplePartKind) == 0 )
  860.             {
  861.                 // Write out the part's content.
  862.                 this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  863.                 // This is our preferrend kind so we don't need to write it again.
  864.                 // Part editors with more than one kind need to test each kind
  865.                 // against the preferred kind to make sure it's been written.
  866.                 preferredKindWritten = kODTrue;
  867.             }
  868.         }
  869.     
  870.         // Write out the part's state information.
  871.         this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  872.  
  873.         // Even if the kind set contains no types we support, we must at least
  874.         // write out our current "preferred" kind.
  875.         if ( preferredKindWritten == kODFalse )
  876.         {
  877.             // Write out the part's preferred content kind, which, for SamplePart,
  878.             // is the only kind.
  879.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  880.         }
  881.     }
  882. }
  883.  
  884. //------------------------------------------------------------------------------
  885. // Method:        ChangeKind
  886. // Origin:        ODPart
  887. //
  888. // Description:    This method is called when the changes the part's primary kind
  889. //                and/or when the part editor is switched via the Info dialog.
  890. //
  891. //                The editor should record the new "preferred" kind and change the
  892. //                UI, if necessary, to allow editing of that kind. Don't write the
  893. //                properties/values/data until the Externalize is called.
  894. //------------------------------------------------------------------------------
  895.  
  896. void SamplePart::ChangeKind( Environment*    ev,
  897.                              ODType            kind )
  898. {
  899.     // SamplePart only has one kind, but we need to make sure the "Preferred Kind"
  900.     // property has the correct value.
  901.     if ( ODISOStrCompare(kind, kSamplePartKind) == 0 )
  902.     {
  903.         // Get our storage unit.
  904.         ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  905.         
  906.         TRY
  907.             // Write out the users preferred kind.
  908.             ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kSamplePartKind);
  909.             
  910.             // Changing our kind dirties our content.
  911.             this->SetDirty(ev);
  912.             
  913.             // Immediately externalize ourselves in the "new" format.
  914.             this->Externalize(ev);
  915.         CATCH_ALL
  916.             // Remove the property and value if something went wrong.
  917.             ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind);
  918.         ENDTRY
  919.     }
  920.     else
  921.         THROW(kODErrInvalidValueType);
  922. }
  923.  
  924. //------------------------------------------------------------------------------
  925. // Method:        ExternalizeStateInfo
  926. // Origin:        SamplePart
  927. //
  928. // Description:    This method is called during externalization of the part. The
  929. //                current "state" of the part should be written out. This "state"
  930. //                information may be lost during Data Interchange operations, so
  931. //                the part needs to recover gracefully if information is missing
  932. //                or incomplete.
  933. //
  934. // Note:        The function StorageUnitSetValue is a macro which simplifies
  935. //                the use of ODByteArrary, which is required by the StorageUnit
  936. //                interface. Look in StorUtil.h/cpp for an example of using the
  937. //                ODByteArray struct.
  938. //------------------------------------------------------------------------------
  939.  
  940. void SamplePart::ExternalizeStateInfo( Environment*        ev,
  941.                                        ODStorageUnit*    storageUnit,
  942.                                        ODDraftKey        key,
  943.                                        ODFrame*            scopeFrame )
  944. {
  945.     SOM_Trace("SamplePart","ExternalizeStateInfo");
  946.  
  947.     ODStorageUnitRef    weakRef;
  948.     ODID                frameID;
  949.     ODID                scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID );
  950.     ODDraft*            fromDraft = ODGetDraft(ev,fSelf);
  951.     
  952.     // Externalize the part's display frame list.
  953.  
  954.     storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  955.                                 kODWeakStorageUnitRefs, 0, kODPosUndefined);
  956.     
  957.     // Persistent object references are stored in a side table, rather than
  958.     // in the property/value stream. Thus, deleting the contents of a value
  959.     // will not "delete" the references previously written to that value. To
  960.     // completely "delete" all references written to the value, we must
  961.     // remove the value and add it back.
  962.     storageUnit->Remove(ev);
  963.     storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  964.  
  965.     CListIterator fiter(fDisplayFrames);
  966.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  967.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  968.     {
  969.         // Get the ID of the frame we are going to weakly reference.
  970.         frameID = proxy->GetID();
  971.         
  972.         // If a draft key exists, then we are being cloned to another draft.
  973.         // We must "weak" clone our display frame and reference the cloned
  974.         // frame. The part re-uses the frameID variable so there aren't two
  975.         // different GetWeakStorageUnitRef calls.
  976.         if ( key )
  977.             frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID);
  978.         
  979.         // Write out weak references to each of the part's display frames.
  980.         storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef);
  981.         TRY
  982.             StorageUnitSetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  983.         CATCH_ALL
  984.             // consume the exception
  985.         ENDTRY
  986.     }
  987. }
  988.  
  989. //------------------------------------------------------------------------------
  990. // Method:        ExternalizeContent
  991. // Origin:        SamplePart
  992. //
  993. // Description:    This method is called during exteralization of the part. The
  994. //                content of the part should be written out.
  995. //
  996. //                The part has no intrinsic content, so the part does nothing.
  997. //                The method is here for completeness.
  998. //------------------------------------------------------------------------------
  999.  
  1000. void SamplePart::ExternalizeContent( Environment*        ev,
  1001.                                      ODStorageUnit*        /*storageUnit*/,
  1002.                                      ODDraftKey            /*key*/,
  1003.                                      ODFrame*            /*scopeFrame*/ )
  1004. {
  1005.     SOM_Trace("SamplePart","ExternalizeContent");
  1006.  
  1007.     // You would write out your part's content after focusing to your
  1008.     // content property.
  1009. }
  1010.  
  1011. //------------------------------------------------------------------------------
  1012. // Method:        CleanseContentProperty
  1013. // Origin:        SamplePart
  1014. //
  1015. // Description:    This method is called during exteralization of the part so that
  1016. //                the part can remove any value in the content property
  1017. //                that it cannot "accurately" write to.
  1018. //
  1019. // Note:        "Additional" values will be added to a part's content property
  1020. //                during Drag & Drop operations.
  1021. //------------------------------------------------------------------------------
  1022.  
  1023. void SamplePart::CleanseContentProperty( Environment*        ev,
  1024.                                          ODStorageUnit*        storageUnit )
  1025. {
  1026.     SOM_Trace("SamplePart","CleanseContentProperty");
  1027.  
  1028.     ODULong numValues;
  1029.     ODULong index;
  1030.     
  1031.     storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1032.                             kODNULL, 0, kODPosAll);
  1033.     
  1034.     numValues = storageUnit->CountValues(ev);
  1035.     
  1036.     for (index = numValues; index >= 1; index--)
  1037.     {
  1038.         // Index from 1 to n through the values.
  1039.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1040.                                 kODNULL, index, kODPosUndefined);
  1041.                                 
  1042.         // Get the ISO type name for the value. The temp object
  1043.         // will automatically delete the returned value when this
  1044.         // scope is exited.
  1045.         TempODValueType value = storageUnit->GetType(ev);
  1046.         
  1047.         // If the value type is not one we support, remove it.
  1048.         if ( ODISOStrCompare(value, kSamplePartKind) != 0 )
  1049.             storageUnit->Remove(ev);
  1050.     }
  1051. }
  1052.  
  1053. //------------------------------------------------------------------------------
  1054. // Method:        CheckAndAddProperties
  1055. // Origin:        SamplePart
  1056. //
  1057. // Description:    This method is called during externalization of the part to
  1058. //                verify that all the properties needed to persistently represent
  1059. //                the current running state of the part.
  1060. //
  1061. //                The part adds the default content property, a preferred editor
  1062. //                property (to aid in part binding), and a display frames
  1063. //                property.
  1064. //
  1065. // Note:        The function StorageUnitSetValue is a macro which simplifies
  1066. //                the use of ODByteArrary, which is required the StorageUnit
  1067. //                interface. Look in StorUtil.h/cpp for an example of using the
  1068. //                ODByteArray struct.
  1069. //------------------------------------------------------------------------------
  1070.  
  1071. void SamplePart::CheckAndAddProperties( Environment*    ev,
  1072.                                         ODStorageUnit*    storageUnit )
  1073. {
  1074.     SOM_Trace("SamplePart","CheckAndAddProperties");
  1075.  
  1076.     // Create our content property and preferred content property kind.
  1077.  
  1078.     if ( !storageUnit->Exists(ev, kODPropContents, kODNULL, 0) )
  1079.         storageUnit->AddProperty(ev, kODPropContents);
  1080.     if ( !storageUnit->Exists(ev, kODPropContents, kSamplePartKind, 0) )
  1081.     {    
  1082.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  1083.         storageUnit->AddValue(ev, kSamplePartKind);
  1084.     }
  1085.  
  1086.     // Since we are setting up the preferred kind property, we just write
  1087.     // out our default "kind" for the editor. We can write out the user
  1088.     // chosen kind in the ExternalizeStateInfo method.
  1089.  
  1090.     if ( !storageUnit->Exists(ev, kODPropPreferredKind, kODISOStr, 0) )
  1091.     {
  1092.         TRY
  1093.             ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kSamplePartKind);
  1094.         CATCH_ALL
  1095.             // Remove the property and value if something went wrong.
  1096.             ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind);
  1097.         ENDTRY
  1098.     }
  1099.         
  1100.     // Add our display frame list.
  1101.     
  1102.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODNULL, 0) )
  1103.         storageUnit->AddProperty(ev, kODPropDisplayFrames);
  1104.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  1105.     {
  1106.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODNULL, 0, kODPosAll);
  1107.         storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  1108.     }
  1109. }
  1110.  
  1111. //------------------------------------------------------------------------------
  1112. // Method:        SetDirty
  1113. // Origin:        SamplePart
  1114. //
  1115. // Description:    This method is called by the part when the content or state of
  1116. //                the part has been modified by the user and the "Save" menu item
  1117. //                should be enabled.
  1118. //------------------------------------------------------------------------------
  1119.  
  1120. void SamplePart::SetDirty( Environment*    ev )
  1121. {
  1122.     SOM_Trace("SamplePart","SetDirty");
  1123.  
  1124.     // There is no need to repeatedly tell the draft we have changed;
  1125.     // once is sufficient.
  1126.     if ( !fDirty && !fReadOnlyStorage )
  1127.     {
  1128.         fDirty = kODTrue;
  1129.         ODGetDraft(ev,fSelf)->SetChangedFromPrev(ev);
  1130.     }
  1131. }
  1132.  
  1133. //------------------------------------------------------------------------------
  1134. // Method:        ReadPartInfo
  1135. // Origin:        ODPart
  1136. //
  1137. // Description:    When a frame is being internalized by the Draft, it will ask the
  1138. //                owner (part) to read in its info annotation on the frame.
  1139. //
  1140. //                The part uses a C++ helper class to encapsulate the information
  1141. //                we store with each frame, so we let it internalize itself from
  1142. //                the storage unit view.
  1143. //------------------------------------------------------------------------------
  1144.  
  1145. ODInfoType SamplePart::ReadPartInfo( Environment*        ev,
  1146.                                      ODFrame*            frame,
  1147.                                      ODStorageUnitView*    storageUnitView )
  1148. {
  1149.     SOM_Trace("SamplePart","ReadPartInfo");
  1150.  
  1151.     CFrameInfo* frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1152.         
  1153.     TRY
  1154.         // Ask the info class to internalize itself.
  1155.         frameInfo->InitFromStorage(ev, storageUnitView);
  1156.     CATCH_ALL
  1157.         // Clean up the allocated memory.
  1158.         ODDeleteObject(frameInfo);
  1159.         // Alert the caller.
  1160.         RERAISE;
  1161.     ENDTRY
  1162.     
  1163.     return (ODInfoType)frameInfo;
  1164. }
  1165.  
  1166. //------------------------------------------------------------------------------
  1167. // Method:        WritePartInfo
  1168. // Origin:        ODPart
  1169. //
  1170. // Description:    When a frame is being externalized by the Draft, it will ask the
  1171. //                owner (part) to write out its info annotation on the frame.
  1172. //
  1173. //                The part uses a C++ helper class to encapsulate the information
  1174. //                we store with each frame, so we let it externalize itself to
  1175. //                the storage unit view.
  1176. //------------------------------------------------------------------------------
  1177.  
  1178. void SamplePart::WritePartInfo( Environment*        ev,
  1179.                                   ODInfoType            partInfo,
  1180.                                 ODStorageUnitView*    storageUnitView )
  1181. {
  1182.     SOM_Trace("SamplePart","WritePartInfo");
  1183.     
  1184.     // Tell our frame info class to write itself out into the pre-
  1185.     // focused storage unit.
  1186.     ((CFrameInfo*) partInfo)->Externalize(ev, storageUnitView);
  1187. }
  1188.  
  1189. //------------------------------------------------------------------------------
  1190. // Method:        ClonePartInfo
  1191. // Origin:        ODPart
  1192. //
  1193. // Description:    When a frame is being cloned by the Draft, it will ask the owner
  1194. //                (part) to clone its info annotation on the frame.
  1195. //
  1196. //                The part uses a C++ helper class to encapsulate the information
  1197. //                we store with each frame, so we let it clone itself to the
  1198. //                storage unit view.
  1199. //------------------------------------------------------------------------------
  1200.  
  1201. void SamplePart::ClonePartInfo( Environment*        ev,
  1202.                                 ODDraftKey            key,
  1203.                                   ODInfoType            partInfo,
  1204.                                 ODStorageUnitView*    storageUnitView,
  1205.                                 ODFrame*            scopeFrame )
  1206. {
  1207.     SOM_Trace("SamplePart","ClonePartInfo");
  1208.     
  1209.     // Tell our frame info class to write itself out into the pre-
  1210.     // focused storage unit.
  1211.     ((CFrameInfo*) partInfo)->CloneInto(ev, key, storageUnitView, scopeFrame);
  1212. }
  1213.  
  1214. //==============================================================================
  1215. #pragma mark    • Layout •
  1216. //==============================================================================
  1217.  
  1218. //------------------------------------------------------------------------------
  1219. // Method:        DisplayFrameAdded
  1220. // Origin:        ODPart
  1221. //
  1222. // Description:    This method is called in response to a frame being created for
  1223. //                the part.
  1224. //
  1225. //                The part records the existence of a new display frame in its
  1226. //                internal display frame list, as well as, verifies that the frame
  1227. //                is "set up" correctly (ie. valid viewType). The part also
  1228. //                creates and stores its "frame info" class in the new frame. 
  1229. //------------------------------------------------------------------------------
  1230.  
  1231. void SamplePart::DisplayFrameAdded( Environment*    ev,
  1232.                                        ODFrame*        frame )
  1233. {
  1234.     SOM_Trace("SamplePart","DisplayFrameAdded");
  1235.  
  1236.     // If we are being embedded in another part, the presentation field
  1237.     // will (most likely) be unset; we need to set it something meaningful.
  1238.     // The view field may also be unset, if so, we prefer to be displayed
  1239.     // in a frame view.
  1240.  
  1241.     if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
  1242.         frame->SetPresentation(ev, gGlobals->fMainPresentation);
  1243.     
  1244.     if ( frame->GetViewType(ev) == kODNullTypeToken )
  1245.         frame->SetViewType(ev, gGlobals->fFrameView);
  1246.         
  1247.     // Hang our "state" info off of the new display frame. We use
  1248.     // the CFrameInfo object for activation, updating, and window
  1249.     // maintenance.
  1250.     CFrameInfo* frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1251.     frame->SetPartInfo(ev, (ODInfoType)frameInfo);
  1252.     
  1253.     // If the frame being added is a root frame, we know that a window
  1254.     // is associated with this frame. Notify ourselves that we need to 
  1255.     // clean it up when the frame goes away.
  1256.     if ( frame->IsRoot(ev) )
  1257.         frameInfo->SetShouldDisposeWindow(kODTrue);
  1258.     
  1259.     // The proxy class will refcount the frame passed to it, so we
  1260.     // don't need to worry about refcounting the display frame.
  1261.     CFrameProxy* proxy = new CFrameProxy;
  1262.     proxy->InitFrameProxy(ev,frame);
  1263.  
  1264.     // Add the proxy to the display frame collection.
  1265.     fDisplayFrames->Add(proxy);
  1266.  
  1267.     // Since we maintain a persistent list of weak references to our
  1268.     // display frames, having one added to the part dirties it.
  1269.     this->SetDirty(ev);
  1270. }
  1271.  
  1272. //------------------------------------------------------------------------------
  1273. // Method:        DisplayFrameConnected
  1274. // Origin:        ODPart
  1275. //
  1276. // Description:    This method is called when one of our display frames, previously
  1277. //                written out, is internalized. This method is called instead of
  1278. //                DisplayFrameAdded because a "new" frame is not being created;
  1279. //                an existing one is being reconstituted.
  1280. //
  1281. //                The part first checks to see if we can match its frame to an
  1282. //                ID in the Display frame list; if so, we put the frame into the
  1283. //                proxy. For frames we do not recognize, just add them.
  1284. //
  1285. // Warning:        This method may be calle,d during editor swapping, with a frame
  1286. //                not recognized by the part. This is ok. Just treat the case as
  1287. //                if a "new" frame were being added to the part.
  1288. //------------------------------------------------------------------------------
  1289.  
  1290. void SamplePart::DisplayFrameConnected( Environment*    ev,
  1291.                                         ODFrame*        frame )
  1292. {
  1293.     SOM_Trace("SamplePart","DisplayFrameConnected");
  1294.  
  1295.     // Iterate over our display collection to match the frame with
  1296.     // an existing proxy with the correct frame ID. If we find it,
  1297.     // replace the ID with the actual frame. If we don't find it,
  1298.     // treat it as a newly "added" frame.
  1299.     ODBoolean found = kODFalse;
  1300.     CListIterator fiter(fDisplayFrames);
  1301.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1302.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1303.     {
  1304.         if ( proxy->GetID() == frame->GetID(ev) )
  1305.         {
  1306.             // The proxy class will refcount the frame passed to it, so we
  1307.             // don't need to worry about refcounting the display frame.
  1308.             proxy->SetFrame(ev,frame);
  1309.             found = kODTrue;
  1310.         }
  1311.     }
  1312.  
  1313.     // Parts typically operate under the assumption that they have previous
  1314.     // knowledge of a frame before it is connected to it. This knowledge
  1315.     // should come from having read in the frame reference when the part
  1316.     // was internalized. If the frame is an "unknown", the part was probably
  1317.     // bound to another editors storage unit because the editor is missing or
  1318.     // the user changed the editor in the Info dialog. 
  1319.     if ( found )
  1320.     {
  1321.         // If a display frame is connected to us with an unrecognizable
  1322.         // presentation, we need to set it to something meaningful.
  1323.     
  1324.         if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
  1325.             frame->SetPresentation(ev, gGlobals->fMainPresentation);
  1326.         
  1327.         if ( frame->IsRoot(ev) )
  1328.         {
  1329.             // If the frame being added is a root frame, we know that a window
  1330.             // is associated with this frame. Notify ourselves that we need to 
  1331.             // clean it up when the frame goes away.
  1332.             CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1333.             frameInfo->SetShouldDisposeWindow(kODTrue);
  1334.             
  1335.             // In addition, we need to verify that the frame is in "frame" view.
  1336.             // If the user dragged an icon from a document to Finder and then
  1337.             // opens the resultant document, the view would be "icon". However
  1338.             // displaying a icon is useless, so we need to change the view to
  1339.             // frame.
  1340.             if ( frame->GetViewType(ev) != gGlobals->fFrameView )
  1341.                 frame->SetViewType(ev, gGlobals->fFrameView);    
  1342.         }
  1343.     }
  1344.     else
  1345.     {
  1346.         // If an unrecognizable frame is connected to us, treat it like a "new"
  1347.         // frame and call our method to add it.
  1348.         this->DisplayFrameAdded(ev, frame);
  1349.     }
  1350. }
  1351.  
  1352. //------------------------------------------------------------------------------
  1353. // Method:        DisplayFrameRemoved
  1354. // Origin:        ODPart
  1355. //
  1356. // Description:    This method is called in response to a frame being removed from
  1357. //                the part.
  1358. //
  1359. //                The part removes the frame from its internal display frame list
  1360. //                and reliquishes any foci that it still owned. Lastly, if the
  1361. //                frame has a source frame (it was the root frame of a part
  1362. //                window), we will record the part window bounds so that any
  1363. //                subsequent part windows opened on the source frame will appear
  1364. //                in the same location.
  1365. //------------------------------------------------------------------------------
  1366.  
  1367. void SamplePart::DisplayFrameRemoved( Environment*    ev,
  1368.                                       ODFrame*        frame )
  1369. {
  1370.     SOM_Trace("SamplePart","DisplayFrameRemoved");
  1371.  
  1372.     TRY
  1373.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1374.     
  1375.         // Make sure the frame going away does not own any foci. Forgetting
  1376.         // to do this, will cause a "refcounting" error when the frame
  1377.         // is deleted by the draft.
  1378.         this->RelinquishAllFoci(ev, frame);
  1379.  
  1380.         // If removing a child window, show zoom rects back to source.
  1381.         // NOTE: This has to be done before CleanupDisplayFrame because 
  1382.         // CleanupDisplayFrame will remove the relationship.
  1383.         if ( frame->IsRoot(ev) && frameInfo->HasSourceFrame() )
  1384.         {
  1385.             TempODWindow window = frame->AcquireWindow(ev);
  1386.             this->ZoomPartWindow(ev, frameInfo->GetSourceFrame(ev),
  1387.                                     window, kWindowClosing);
  1388.         }
  1389.                 
  1390.         // Clean up the display frame.
  1391.         this->CleanupDisplayFrame(ev, frame, kFrameRemoved);
  1392.         // Clean up any associated window.
  1393.         this->CleanupWindow(ev, frame);
  1394.         // Dispose of the frame's runtime state info.
  1395.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1396.         ODDeleteObject(frameInfo);
  1397.         
  1398.         // Remove the display frame from our collection.
  1399.         CListIterator fiter(fDisplayFrames);
  1400.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1401.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1402.         {
  1403.             if ( ODObjectsAreEqual(ev, proxy->GetFrame(ev), frame) )
  1404.             {
  1405.                 // Delete the proxy object and its contents. The frame's
  1406.                 // refcount will be decremented in the proxy destructor.
  1407.                 fiter.RemoveCurrent();
  1408.                 delete proxy;
  1409.             }
  1410.         }
  1411.  
  1412.         // Since we maintain a persistent list of weak references to our
  1413.         // display frames, having one removed from the part dirties it.
  1414.         this->SetDirty(ev);
  1415.     
  1416.     CATCH_ALL
  1417.         // Alert the user of the problem.
  1418.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1419.         // Change the exception value, so the DocShell doesn't display an
  1420.         // error dialog.
  1421.         SetErrorCode(kODErrAlreadyNotified);
  1422.         // Alert the caller.
  1423.         RERAISE;
  1424.     ENDTRY
  1425. }
  1426.  
  1427. //------------------------------------------------------------------------------
  1428. // Method:        DisplayFrameClosed
  1429. // Origin:        ODPart
  1430. //
  1431. // Description:    This method is called in response to a frame being closed as a
  1432. //                result of the document having been closed by the user.
  1433. //
  1434. //                The part behaves much the same way that it would if a frame were
  1435. //                removed (see above), except that we don't need to cache runtime
  1436. //                information. 
  1437. //------------------------------------------------------------------------------
  1438.  
  1439. void SamplePart::DisplayFrameClosed( Environment*    ev,
  1440.                                      ODFrame*        frame )
  1441. {
  1442.     SOM_Trace("SamplePart","DisplayFrameClosed");
  1443.  
  1444.     TRY
  1445.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1446.     
  1447.         // Make sure the frame going away does not own any foci. Forgetting
  1448.         // to do this, will cause a "refcounting" error when the frame
  1449.         // is deleted by the draft.
  1450.         this->RelinquishAllFoci(ev, frame);
  1451.  
  1452.         // Clean up the display frame.
  1453.         this->CleanupDisplayFrame(ev, frame, kFrameClosed);
  1454.         // Clean up any associated window.
  1455.         this->CleanupWindow(ev, frame);
  1456.         // Dispose of the frame's runtime state info.
  1457.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1458.         ODDeleteObject(frameInfo);
  1459.         
  1460.         // Remove the display frame from our collection.
  1461.         CListIterator fiter(fDisplayFrames);
  1462.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1463.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1464.         {
  1465.             if ( proxy->GetID() == frame->GetID(ev) )
  1466.             {
  1467.                 // Release the frame reference, but don't get rid of the
  1468.                 // proxy object because "closed" frames may be reconnected
  1469.                 // before the document is really closed.
  1470.                 proxy->Purge(ev);
  1471.             }
  1472.         }
  1473.         
  1474.     CATCH_ALL
  1475.         // Alert the user of the problem.
  1476.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1477.         // Change the exception value, so the DocShell doesn't display an
  1478.         // error dialog.
  1479.         SetErrorCode(kODErrAlreadyNotified);
  1480.         // Alert the caller.
  1481.         RERAISE;
  1482.     ENDTRY
  1483. }
  1484.  
  1485. //------------------------------------------------------------------------------
  1486. // Method:        CleanupDisplayFrame
  1487. // Origin:        SamplePart
  1488. //
  1489. // Description:    This method is called when a frame has been closed or removed.
  1490. //                The method cleans up the references and state information stored
  1491. //                in the CFrameInfo class.
  1492. //------------------------------------------------------------------------------
  1493.  
  1494. void SamplePart::CleanupDisplayFrame( Environment*    ev,
  1495.                                       ODFrame*        frame,
  1496.                                       ODBoolean        frameRemoved )
  1497. {
  1498.     SOM_Trace("SamplePart","CleanupDisplayFrame");
  1499.  
  1500.     ODError        error = noErr;
  1501.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1502.  
  1503.     TRY
  1504.         // If we are the root of a child window, we need to notify
  1505.         // our source frame that we are going away.
  1506.         if ( frameInfo->HasSourceFrame() )
  1507.         {
  1508.             ODFrame* sourceFrame = frameInfo->GetSourceFrame(ev);
  1509.             CFrameInfo* sourceFrameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1510.  
  1511.             if ( frameRemoved )
  1512.             {
  1513.                 // Invalidate the source frame. We do this because the
  1514.                 // source frame may have a unique display when it has
  1515.                 // been opened into a part window. This forces the
  1516.                 // frame to redraw "not opened".
  1517.                 sourceFrame->Invalidate(ev, kODNULL, kODNULL);
  1518.             }
  1519.             
  1520.             // Tell the source frame that its dependent is going away.
  1521.             sourceFrameInfo->ReleaseDependentFrame(ev);            
  1522.  
  1523.             // Release our reference to the source frame.
  1524.             frameInfo->ReleaseSourceFrame(ev);
  1525.  
  1526.             // If the frame is the root, it is a part window going away
  1527.             // and we need to notify our source frame that it no longer
  1528.             // has a part window.
  1529.             if ( frame->IsRoot(ev) )
  1530.                 sourceFrameInfo->SetPartWindow(ev, kODNULL);
  1531.         }
  1532.     CATCH_ALL
  1533.         error = ErrorCode();
  1534.     ENDTRY
  1535.     
  1536.     TRY
  1537.         // If the frame was removed from the document, we need to remove
  1538.         // any child window displaying that frame.
  1539.         if ( frameRemoved )
  1540.         {
  1541.             // If we have a child window, we need to close it.
  1542.             ODWindow* window = frameInfo->AcquirePartWindow(ev);
  1543.  
  1544.             if ( window )
  1545.             {
  1546.                 frameInfo->SetPartWindow(ev, kODNULL);
  1547.                 window->CloseAndRemove(ev);
  1548.             }
  1549.         }
  1550.     CATCH_ALL
  1551.         error = ErrorCode();
  1552.     ENDTRY
  1553.  
  1554.     TRY
  1555.         // If we have dependent frames, we need to notify them that we
  1556.         // are going away.
  1557.     
  1558.         if ( frameInfo->HasDependentFrame() )
  1559.         {
  1560.             // Get the frame that is dependent on this one. We can safely
  1561.             // do this because we only reference our own display frames.
  1562.             ODFrame* dependentFrame = frameInfo->GetDependentFrame(ev);
  1563.             CFrameInfo* dependentFrameInfo = (CFrameInfo*) dependentFrame->GetPartInfo(ev);
  1564.  
  1565.             // Tell the dependent frame that its source is going away.
  1566.             dependentFrameInfo->ReleaseSourceFrame(ev);
  1567.             
  1568.             // Release our reference to the dependent frame.
  1569.             frameInfo->ReleaseDependentFrame(ev);
  1570.         }
  1571.     CATCH_ALL
  1572.         error = ErrorCode();
  1573.     ENDTRY
  1574.     
  1575.     // If anything went wrong, signal an error.
  1576.     THROW_IF_ERROR(error);
  1577. }
  1578.  
  1579. //------------------------------------------------------------------------------
  1580. // Method:        AttachSourceFrame
  1581. // Origin:        ODPart
  1582. //
  1583. // Description:    If the part which we are contained in is opened into a part
  1584. //                window, it is required to iterate over its embedded frames and
  1585. //                add new display frames in the part window. After each new
  1586. //                embedded frame is created, this method will be called.
  1587. //
  1588. //                Given all that, and given our lack of interesting
  1589. //                content, we just validate the frame and attach it to its source.
  1590. //------------------------------------------------------------------------------
  1591.  
  1592. void SamplePart::AttachSourceFrame( Environment*    ev,
  1593.                                     ODFrame*        frame,
  1594.                                     ODFrame*        sourceFrame )
  1595. {
  1596.     SOM_Trace("SamplePart","AttachSourceFrame");
  1597.  
  1598.     // Tell the new frame about its source.
  1599.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1600.     frameInfo->SetSourceFrame(ev, sourceFrame);
  1601.     
  1602.     // And tell the source about its new dependent.
  1603.     frameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1604.     frameInfo->SetDependentFrame(ev, frame);
  1605.     
  1606.     // In both cases, refcounting of the frame and sourceFrame is
  1607.     // handled by the CFrameInfo class.
  1608. }
  1609.  
  1610. //------------------------------------------------------------------------------
  1611. // Method:        ViewTypeChanged
  1612. // Origin:        ODPart
  1613. //
  1614. // Description:    This method is called in response to one of our display frame's
  1615. //                viewType field being modified. We call this method on ourselves
  1616. //                when new display frames are added, but it call also be called
  1617. //                when the user changes the view in the "part info" dialog.
  1618. //------------------------------------------------------------------------------
  1619.  
  1620. void SamplePart::ViewTypeChanged( Environment*    ev,
  1621.                                   ODFrame*        frame )
  1622. {
  1623.     SOM_Trace("SamplePart","ViewTypeChanged");
  1624.  
  1625.     // Change this frame's used shape to match the new view setting.
  1626.     TempODShape newUsedShape = this->CalcNewUsedShape(ev, frame);    
  1627.  
  1628.     frame->Invalidate(ev, kODNULL, kODNULL);
  1629.     frame->ChangeUsedShape(ev, newUsedShape, kODNULL);
  1630.     frame->Invalidate(ev, kODNULL, kODNULL);
  1631. }
  1632.  
  1633. //------------------------------------------------------------------------------
  1634. // Method:        CalcNewUsedShape
  1635. // Origin:        SamplePart
  1636. //
  1637. // Description:    This method is called in response to one of display frame's view
  1638. //                being changed. The method calculates the appropriate usedShape
  1639. //                for the new view type.
  1640. //------------------------------------------------------------------------------
  1641.  
  1642. ODShape* SamplePart::CalcNewUsedShape( Environment*    ev,
  1643.                                          ODFrame*        frame )
  1644. {
  1645.     SOM_Trace("SamplePart","CalcNewUsedShape");
  1646.  
  1647.     ODShape* usedShape = kODNULL;        ODVolatile(usedShape);
  1648.     RgnHandle usedRgn;                    ODVolatile(usedRgn);
  1649.     
  1650.     // If the view is "frame", we intentionally return a nil shape;
  1651.     // doing so, will reset the used shape to equal the frame shape.
  1652.  
  1653.     ODTypeToken view = frame->GetViewType(ev);
  1654.  
  1655.     if ( view == gGlobals->fLargeIconView ||
  1656.             view == gGlobals->fSmallIconView ||
  1657.             view == gGlobals->fThumbnailView )
  1658.     {
  1659.         TRY
  1660.             Rect bounds;
  1661.             usedRgn = ODNewRgn();
  1662.  
  1663.             if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  1664.             {
  1665.                 CUsingLibraryResources res;
  1666.  
  1667.                 // Set the bounds rect for the icon size.
  1668.                 SetRect(&bounds, 0, 0,
  1669.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize,
  1670.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize);
  1671.  
  1672.                 // Convert the icon mask into a Region.
  1673.                 THROW_IF_ERROR( IconIDToRgn(usedRgn, &bounds, atAbsoluteCenter, kBaseResourceID) );
  1674.             }
  1675.             else if ( view == gGlobals->fThumbnailView )
  1676.             {    
  1677.                 PicHandle thumbnail = this->GenerateThumbnail(ev, frame);
  1678.  
  1679.                 if ( thumbnail )
  1680.                     bounds = (**thumbnail).picFrame;
  1681.                 else
  1682.                     SetRect(&bounds, 0, 0, kODThumbnailSize, kODThumbnailSize);
  1683.                     
  1684.                 RectRgn(usedRgn,&bounds);
  1685.             }
  1686.         
  1687.             usedShape = frame->CreateShape(ev);
  1688.             usedShape->SetQDRegion(ev, usedRgn);
  1689.                             
  1690.         CATCH_ALL
  1691.             ODSafeReleaseObject(usedShape);
  1692.             ODDisposeHandle((ODHandle)usedRgn);
  1693.             usedShape = kODNULL;
  1694.         ENDTRY
  1695.     }
  1696.         
  1697.     return usedShape;
  1698. }
  1699.  
  1700. //------------------------------------------------------------------------------
  1701. // Method:        UpdateFrame
  1702. // Origin:        SamplePart
  1703. //
  1704. // Description:    This method is called in response to one of our
  1705. //------------------------------------------------------------------------------
  1706.  
  1707. void SamplePart::UpdateFrame( Environment*    ev,
  1708.                               ODFrame*        frame,
  1709.                               ODTypeToken    view,
  1710.                               ODShape*        usedShape )
  1711. {
  1712.     SOM_Trace("SamplePart","UpdateFrame");
  1713.  
  1714.     TRY
  1715.         // Update the frame to have the new view and UsedShape.
  1716.         frame->Invalidate(ev, kODNULL, kODNULL);
  1717.         frame->SetViewType(ev, view);
  1718.         frame->ChangeUsedShape(ev, usedShape, kODNULL);
  1719.         frame->Invalidate(ev, kODNULL, kODNULL);
  1720.     CATCH_ALL
  1721.         // Failing isn't great, but we can live with it, so don't set ev.
  1722.     ENDTRY
  1723. }
  1724.  
  1725. //------------------------------------------------------------------------------
  1726. // Method:        FrameShapeChanged
  1727. // Origin:        ODPart
  1728. //
  1729. // Description:    This method is called in response to a frame's shape being
  1730. //                altered, either by the user or the part we are embedded in.
  1731. //
  1732. //                To keep all dependent frames in sync, we need to propogate the
  1733. //                new frame shape the frames dependent on the changed frame. This
  1734. //                is done by observing the display frames stored in the frame info
  1735. //                and calling RequestFrameShape for each.
  1736. //------------------------------------------------------------------------------
  1737.  
  1738. void SamplePart::FrameShapeChanged( Environment*    ev,
  1739.                                     ODFrame*        frame )
  1740. {
  1741.     SOM_Trace("SamplePart","FrameShapeChanged");
  1742.  
  1743.     // Adjust the "used" shape for the new frame shape.
  1744.     TempODShape usedShape = this->CalcNewUsedShape(ev, frame);
  1745.     frame->ChangeUsedShape(ev, usedShape, kODNULL);
  1746. }
  1747.  
  1748. //------------------------------------------------------------------------------
  1749. // Method:        Open
  1750. // Origin:        ODPart
  1751. //
  1752. // Description:    This method is called when OpenDoc, a containing part, or the
  1753. //                active editor would like to open a frame into a seperate window.
  1754. //                If a source frame is passed into this method, the editor is
  1755. //                being asked one of two things. If the frame is the root, we are
  1756. //                being asked to open an existing document. If the frame is not
  1757. //                the root, we are being asked to open a part window. If a source
  1758. //                frame is not specified, the editor is being asked to open a new
  1759. //                window.
  1760. //------------------------------------------------------------------------------
  1761.  
  1762. ODID SamplePart::Open( Environment*        ev,
  1763.                        ODFrame*            frame )
  1764. {
  1765.     SOM_Trace("SamplePart","Open");
  1766.  
  1767.     ODID windowID;
  1768.     TempODWindow window(kODNULL);
  1769.  
  1770.     WindowProperties* windowProperties = kODNULL;
  1771.     ODVolatile(windowProperties);
  1772.  
  1773.     TRY
  1774.         // Because the frame parameter being passed to us can be one of
  1775.         // three things, we must determine what it is; either the root
  1776.         // frame of a existing document, the source frame for a part
  1777.         // window, or null if we are opening a new document.
  1778.     
  1779.         if ( frame == kODNULL )
  1780.         {
  1781.             // Calculate the bounding rectangle for a new window
  1782.             Rect windowRect = this->CalcPartWindowSize(ev, kODNULL);
  1783.             // Get the default setting for a document window.
  1784.             windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  1785.             // Create a Mac Window and register it with OpenDoc.
  1786.             window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  1787.         }
  1788.         else if ( frame->IsRoot(ev) )
  1789.         {
  1790.             // Get the previously saved settings for the document window.
  1791.             windowProperties = this->GetSavedWindowProperties(ev, frame);
  1792.             
  1793.             if ( windowProperties == kODNULL )
  1794.             {
  1795.                 // Calculate the bounding rectangle for a new window
  1796.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  1797.                 // Get the default setting for a document window.
  1798.                 windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  1799.             }
  1800.  
  1801.             // Create a Mac Window and register it with OpenDoc.
  1802.             window = this->CreateWindow(ev, frame, kODFrameObject, windowProperties);
  1803.             
  1804.             // We release the source frame here because we didn't call
  1805.             // EndGetWindowProperties and becuase we are done with it.
  1806.             ODReleaseObject(ev, windowProperties->sourceFrame);
  1807.         }
  1808.         else // frame is a source frame
  1809.         {
  1810.             window = this->AcquireFramesWindow(ev, frame);
  1811.     
  1812.             if ( window == kODNULL )
  1813.             {
  1814.                 // Calculate the bounding rectangle for a new window
  1815.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  1816.                 // Get the default setting for a document window.
  1817.                 windowProperties = this->GetDefaultWindowProperties(ev, frame, &windowRect);
  1818.                 // Create a Mac Window and register it with OpenDoc.
  1819.                 window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  1820.                 
  1821.                 // Tell the source frame that it is opened in a part window.
  1822.                 CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1823.                 frameInfo->SetPartWindow(ev, window);
  1824.     
  1825.                 this->ZoomPartWindow(ev, frame, window, kWindowOpening);
  1826.             }
  1827.         }
  1828.     
  1829.         // Create the window's root facet.
  1830.         window->Open(ev);
  1831.         // Make the window visible.
  1832.         window->Show(ev);
  1833.         // Activate and select the window.
  1834.         window->Select(ev);
  1835.     
  1836.         // Cleanup allocate memory.
  1837.         ODDeleteObject(windowProperties);
  1838.         
  1839.         // Get window id to return.
  1840.         windowID = (window ? window->GetID(ev) : kODNULLID);
  1841.     
  1842.     CATCH_ALL
  1843.         // If we threw early, the source frame's refcount may be too high.
  1844.         if ( windowProperties )
  1845.             ODSafeReleaseObject(windowProperties->sourceFrame);
  1846.         // Cleanup the created items.
  1847.         ODDeleteObject(windowProperties);
  1848.         windowID = kODNULLID;
  1849.         // Alert the caller.
  1850.         RERAISE;
  1851.     ENDTRY
  1852.  
  1853.     return windowID;
  1854. }
  1855.  
  1856. //------------------------------------------------------------------------------
  1857. // Method:        AcquireFramesWindow
  1858. // Origin:        SamplePart
  1859. //
  1860. // Description:    This method is called by the part when a frame, that has been
  1861. //                previously opened, is being opened again.
  1862. //
  1863. //                The method retrieves the existing window for the frame and
  1864. //                returns it.                
  1865. //------------------------------------------------------------------------------
  1866.  
  1867. ODWindow* SamplePart::AcquireFramesWindow(    Environment*    ev,
  1868.                                                ODFrame*        frame )
  1869. {
  1870.     SOM_Trace("SamplePart","GetFramesWindow");
  1871.  
  1872.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1873.     ODWindow* window = frameInfo->AcquirePartWindow(ev);
  1874.  
  1875.     return window;
  1876. }
  1877.     
  1878. //------------------------------------------------------------------------------
  1879. // Method:        CreateWindow
  1880. // Origin:        SamplePart
  1881. //
  1882. // Description:    This method is called by the part when a window needs to be
  1883. //                created for a frame being opened.
  1884. //
  1885. //                The part uses the information passed in windowProperties to 
  1886. //                create the appropriate window. The generated window is
  1887. //                registered with OpenDoc as a new window (RegisterWindow) or as a
  1888. //                window from an existing document (RegisterWindowForFrame).
  1889. //------------------------------------------------------------------------------
  1890.  
  1891. ODWindow* SamplePart::CreateWindow( Environment*         ev,
  1892.                                     ODFrame*            frame,
  1893.                                     ODType                frameType,
  1894.                                     WindowProperties*    windowProperties)
  1895. {
  1896.     SOM_Trace("SamplePart","CreateWindow");
  1897.  
  1898.     ODPlatformWindow    platformWindow    = kODNULL;
  1899.     ODWindow*            window            = kODNULL;
  1900.     
  1901.     // Using the name and the calculated rectangle, create a new window.
  1902.     // Note that we are allocating the window record in temp mem using
  1903.     // the OpenDoc memory mgr. This helps reduce app heap usage.
  1904.     // In addition, OpenDoc requires that all new windows be initially hidden
  1905.     // so that it can correctly layer windows/palettes.
  1906.     platformWindow = NewCWindow((Ptr)ODNewPtr(sizeof(WindowRecord)),
  1907.                                 &(windowProperties->boundsRect),
  1908.                                 windowProperties->title,
  1909.                                 kODFalse, /* visible */
  1910.                                 windowProperties->procID,
  1911.                                 (WindowPtr)-1L,
  1912.                                 windowProperties->hasCloseBox,
  1913.                                 windowProperties->refCon);
  1914.  
  1915.     if ( platformWindow )
  1916.     {
  1917.         TRY
  1918.             ODWindowState* windowState = ODGetSession(ev,fSelf)->GetWindowState(ev);
  1919.             
  1920.             // Shoud the window be saved in the document? Yes if the root frame is
  1921.             // persistent.
  1922.             ODBoolean saveWindow = (ODISOStrCompare(frameType,kODFrameObject) == 0);
  1923.             
  1924.             // Tell the window object that we will be disposing the window record
  1925.             // when the root frame is closed/removed.
  1926.             ODBoolean shouldDispose = kODFalse;
  1927.                                 
  1928.             // Determine whether we are creating a new window (frame is null),
  1929.             // or opening a previous saved window (frame is valid).
  1930.             
  1931.             if ( frame == kODNULL )
  1932.             {                                
  1933.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  1934.                 window = windowState->
  1935.                             RegisterWindow(ev, 
  1936.                                 platformWindow,                    // Macintosh WindowPtr
  1937.                                 frameType,                        // Frame type (Persistent/Non-persistent)
  1938.                                 windowProperties->isRootWindow,    // Is this a document window?
  1939.                                 windowProperties->isResizable,    // Is this window resizeable?
  1940.                                 windowProperties->isFloating,    // Is this window floating?
  1941.                                 saveWindow,                        // Should this window be persistent?
  1942.                                 shouldDispose,                    // (see comment above)
  1943.                                 fSelf,                            // Part reference to us
  1944.                                 gGlobals->fFrameView,            // What view should the window have?
  1945.                                 gGlobals->fMainPresentation,    // What presentation should the window have?
  1946.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  1947.             }
  1948.             else
  1949.             {
  1950.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  1951.                 window = windowState->
  1952.                             RegisterWindowForFrame(ev, 
  1953.                                 platformWindow,                    // Macintosh WindowPtr
  1954.                                 frame,                             // Frame type (Persistent/Non-persistent)
  1955.                                 windowProperties->isRootWindow,    // Is this a document window?
  1956.                                 windowProperties->isResizable,    // Is this window resizeable?
  1957.                                 windowProperties->isFloating,    // Is this window floating?
  1958.                                 saveWindow,                        // Should this window be persistent?
  1959.                                 shouldDispose,                    // (see comment above)
  1960.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  1961.             }
  1962.             
  1963.         CATCH_ALL
  1964.             // Cleanup Macintosh Window.
  1965.             CloseWindow(platformWindow);
  1966.             ODDisposePtr(platformWindow);
  1967.             // Get the right error message for the problem.
  1968.             ODSShort errMsgNum = (!frame && windowProperties->sourceFrame)
  1969.                                     ? kErrCantOpenPartWindow : kErrCantOpenDocWindow;
  1970.             // Alert the user of the problem.
  1971.             this->DoDialogBox(ev, frame, kErrorBoxID, errMsgNum);
  1972.             // Change the exception value, so the DocShell doesn't display an
  1973.             // error dialog.
  1974.             SetErrorCode(kODErrAlreadyNotified);
  1975.             // Alert the caller.
  1976.             RERAISE;
  1977.         ENDTRY
  1978.     }
  1979.  
  1980.     return window;
  1981. }
  1982.     
  1983. //------------------------------------------------------------------------------
  1984. // Method:        CleanupWindow
  1985. // Origin:        SamplePart
  1986. //
  1987. // Description:    This method is called by the part when a window needs to be
  1988. //                cleaned up for a frame being closed/removed.
  1989. //
  1990. //                The part deallocates the window buffer allocated in the
  1991. //                CreateWindow() method.
  1992. //------------------------------------------------------------------------------
  1993.  
  1994. void SamplePart::CleanupWindow( Environment*     ev,
  1995.                                 ODFrame*        frame )
  1996. {
  1997.     SOM_Trace("SamplePart","CleanupWindow");
  1998.     
  1999.        TRY
  2000.         CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2001.         if ( frameInfo->ShouldDisposeWindow() )
  2002.         {
  2003.             TempODWindow window = frame->AcquireWindow(ev);
  2004.             THROW_IF_NULL(window);
  2005.             
  2006.             ODPlatformWindow windowPtr = window->GetPlatformWindow(ev);
  2007.             CloseWindow(windowPtr);
  2008.             ODDisposePtr(windowPtr);
  2009.         }
  2010.     CATCH_ALL
  2011.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrWindowGone);
  2012.         // consume excpetion because it's not fatal.
  2013.     ENDTRY
  2014. }
  2015.  
  2016. //------------------------------------------------------------------------------
  2017. // Method:        GetDefaultWindowProperties
  2018. // Origin:        SamplePart
  2019. //
  2020. // Description:    This method is called by the part when a new window is being
  2021. //                created. The method examines the frame which is being opened
  2022. //                a generates the default window parameters to pass to the
  2023. //                Mac Toolbox.
  2024. //------------------------------------------------------------------------------
  2025.  
  2026. WindowProperties*
  2027. SamplePart::GetDefaultWindowProperties( Environment*     ev,
  2028.                                         ODFrame*        sourceFrame,
  2029.                                         Rect*            windowRect )
  2030. {
  2031.     SOM_Trace("SamplePart","GetDefaultWindowProperties");
  2032.     
  2033.     WindowProperties* windowProperties = new WindowProperties;
  2034.  
  2035.     TRY
  2036.         // Calculate the offset for the window based on the sourceFrame.    
  2037.         if ( sourceFrame )
  2038.             this->CalcPartWindowPosition(ev, sourceFrame, windowRect);
  2039.         else
  2040.             OffsetRect(windowRect, kALittleNudge,
  2041.                         GetMBarHeight() + kMacWindowTitleBarHeight);    
  2042.     
  2043.         // Set the window bounds based on the calculated rect.
  2044.         windowProperties->boundsRect = *windowRect;
  2045.     
  2046.         // Get the part's name to use for the new window.
  2047.         TempODIText windowName = GetPartName(ev, fSelf, kSamplePartCategory);
  2048.         // Convert the ODIText into a Pascal string.
  2049.         GetITextString(windowName, windowProperties->title);
  2050.         
  2051.         // Fill in the other fields of the Window Properties struct.
  2052.         
  2053.         windowProperties->procID = zoomDocProc;
  2054.         windowProperties->hasCloseBox = kODTrue;
  2055.         windowProperties->refCon = (long) kODNULL;
  2056.         windowProperties->wasVisible = kODFalse;
  2057.         windowProperties->isResizable = kODTrue;
  2058.         windowProperties->isFloating = kODFalse;
  2059.         windowProperties->isRootWindow = sourceFrame ? kODFalse : kODTrue;
  2060.         windowProperties->shouldShowLinks = kODFalse;
  2061.         windowProperties->sourceFrame = sourceFrame;
  2062.     CATCH_ALL
  2063.         // Clean up and...
  2064.         ODDeleteObject(windowProperties);
  2065.         // Alert the caller.
  2066.         RERAISE;
  2067.     ENDTRY
  2068.     
  2069.     return windowProperties;
  2070. }
  2071.  
  2072. //------------------------------------------------------------------------------
  2073. // Method:        GetSavedWindowProperties
  2074. // Origin:        SamplePart
  2075. //
  2076. // Description:    This method is called by the part to read in saved information
  2077. //                for a window from an existing document.
  2078. //------------------------------------------------------------------------------
  2079.  
  2080. WindowProperties* SamplePart::GetSavedWindowProperties( Environment*     ev,
  2081.                                                           ODFrame*        frame )
  2082. {
  2083.     SOM_Trace("SamplePart","GetSavedWindowProperties");
  2084.  
  2085.     WindowProperties* windowProperties = new WindowProperties;
  2086.     
  2087.     // If we fail to load the window properties from storage, delete
  2088.     // the structure so the calling code will behave appropriately.    
  2089.     if ( BeginGetWindowProperties(ev, frame, windowProperties) )
  2090.     {    
  2091.         // Note: We don't call EndGetWindowProperties because it releases the
  2092.         // source frame, which we will need after this method returns.
  2093.         
  2094.         // Get the part's name to use for the new window.
  2095.         TempODIText windowName = GetPartName(ev, fSelf, kSamplePartCategory);
  2096.         // Convert the ODIText into a Pascal string.
  2097.         GetITextString(windowName, windowProperties->title);
  2098.     
  2099.         // Verify the window is still visible on a monitor.
  2100.         
  2101.         RgnHandle windowRgn = ODNewRgn();
  2102.         ODBoolean repositionWindow = kODFalse;
  2103.         
  2104.         // We are only concerned with the window's title bar being
  2105.         // visible, so calcuate the titlebar rect from the current
  2106.         // window bounds.
  2107.         Rect adjustedBounds = windowProperties->boundsRect;
  2108.         adjustedBounds.bottom = adjustedBounds.top;
  2109.         adjustedBounds.top -= kMacWindowTitleBarHeight;
  2110.         
  2111.         // Intersect the monitor's region
  2112.         RectRgn(windowRgn, &adjustedBounds);
  2113.         SectRgn(windowRgn, GetGrayRgn(), windowRgn);
  2114.         
  2115.         if ( !EmptyRgn(windowRgn) )
  2116.         {
  2117.             // If the visible portion of the window is too small, we need
  2118.             // to reposition it.
  2119.             Rect intersectedBounds = (**windowRgn).rgnBBox;
  2120.             if ( (intersectedBounds.right-intersectedBounds.left < kMinHorzVisPortion) ||
  2121.                     (intersectedBounds.bottom-intersectedBounds.top < kMinVertVisPortion) )
  2122.                 repositionWindow = kODTrue;
  2123.         }
  2124.         else
  2125.         {
  2126.             // If the window is completely offscreen, we need to reposition it.
  2127.             repositionWindow = kODTrue;
  2128.         }
  2129.         ODDisposeHandle((ODHandle)windowRgn);
  2130.         
  2131.         // If not, we need to move it so the user can see it.
  2132.         if ( repositionWindow )
  2133.         {
  2134.             Rect windowRect = (windowProperties->boundsRect);
  2135.             // Move the window to {0,0} coordinates.
  2136.             OffsetRect(&windowRect, -windowRect.left, -windowRect.top);
  2137.             // Now move the window to the default window position.
  2138.             OffsetRect(&windowRect, kALittleNudge, GetMBarHeight() + kMacWindowTitleBarHeight);
  2139.             // Save the new window position in our windowProperties.
  2140.             windowProperties->boundsRect = windowRect;
  2141.         }
  2142.     }
  2143.     else
  2144.     {
  2145.         // If we were unable to re-load window properties, dispose of the
  2146.         // struct.
  2147.         ODDeleteObject(windowProperties);
  2148.     }
  2149.         
  2150.     return windowProperties;
  2151. }
  2152.  
  2153. //------------------------------------------------------------------------------
  2154. // Method:        CalcPartWindowSize
  2155. // Origin:        SamplePart
  2156. //
  2157. // Description:    This method is called by the part to determine what size a new
  2158. //                window shoud be.
  2159. //------------------------------------------------------------------------------
  2160.  
  2161. Rect SamplePart::CalcPartWindowSize( Environment*    ev,
  2162.                                      ODFrame*        sourceFrame )
  2163. {
  2164.     SOM_Trace("SamplePart","CalcPartWindowSize");
  2165.  
  2166.     const ODSShort kOnePageWidth = 600;
  2167.     
  2168.     Rect    windowRect;
  2169.     ODRect    frameRect;
  2170.     
  2171.     // If a source frame is given, the part is being asked to open one of
  2172.     // its display frames into a part window. Otherwise, we are being opened
  2173.     // as the root frame of the current document and should size the window
  2174.     // accordingly.
  2175.  
  2176.     // Set up the child window's size to be that of the display frame being opened.
  2177.     if ( sourceFrame )
  2178.     {
  2179.         // Retrieve the fixed point bounding box for the frame.
  2180.         TempODShape frameShape = sourceFrame->AcquireFrameShape(ev, kODNULL);
  2181.         frameShape->GetBoundingBox(ev, &frameRect);
  2182.         
  2183.         // Convert that into a Quickdraw rectangle.
  2184.         FixedToIntRect(frameRect, windowRect);
  2185.     }
  2186.     // Otherwise, just open a large window.
  2187.     else
  2188.     {
  2189.         // (3 * kODLargeIconSize) prevents the window from covering the volume
  2190.         // icons on the desktop which is a violation of Macintosh HI Guidelines.
  2191.         
  2192.         SetRect(&windowRect, 0, 0,
  2193.                   ODQDGlobals.screenBits.bounds.right - (3 * kODLargeIconSize),
  2194.                   ODQDGlobals.screenBits.bounds.bottom
  2195.                       - GetMBarHeight() - kMacWindowTitleBarHeight - kALittleNudge);        
  2196.         
  2197.         if ( windowRect.right - windowRect.left > kOnePageWidth )
  2198.             windowRect.right = windowRect.left + kOnePageWidth;
  2199.     }
  2200.     
  2201.     return windowRect;
  2202. }
  2203.  
  2204. //------------------------------------------------------------------------------
  2205. // Method:        CalcPartWindowPosition
  2206. // Origin:        SamplePart
  2207. //
  2208. // Description:    This method is called by the part to determine where to align
  2209. //                the new window (top left corner of the screen or tiled to a
  2210. //                frame).
  2211. //------------------------------------------------------------------------------
  2212.  
  2213. Rect SamplePart::CalcPartWindowPosition( Environment*    ev,
  2214.                                          ODFrame*        frame,
  2215.                                          Rect*            partWindowBounds )
  2216. {
  2217.     SOM_Trace("SamplePart","CalcPartWindowPosition");
  2218.  
  2219.     ODFacet*        activeFacet;
  2220.     ODShape*        frameShape;
  2221.     ODRect            bbox;
  2222.     Rect            bounds;
  2223.     
  2224.     // We need to know which facet of the frame we are opening to position
  2225.     // the child window.
  2226.     activeFacet = this->GetActiveFacetForFrame(ev, frame);
  2227.     
  2228.     // This should never occur, but if it did, it would be fatal.
  2229.     // So we will just pass back the same rectangle.
  2230.     if ( activeFacet == kODNULL )
  2231.         return *partWindowBounds;
  2232.     
  2233.     // For the purposes of tiling, we need the to know the area of the
  2234.     // document the frame occupies. We do this by getting the bouding
  2235.     // box and offsetting it by the aggregate external window transform
  2236.     // of the facet.
  2237.     
  2238.     frameShape = activeFacet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
  2239.     TempODTransform windowFrameTransform = activeFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2240.     TempODShape boundsShape = ODCopyAndRelease(ev, frameShape);
  2241.  
  2242.     // Translate the bounds rect into window coordinates.
  2243.     boundsShape->Transform(ev, windowFrameTransform);
  2244.     
  2245.     // Get and convert the bounding box into a QuickDraw rectangle.
  2246.     boundsShape->GetBoundingBox(ev, &bbox);
  2247.     FixedToIntRect(bbox, bounds);
  2248.         
  2249.     // We then call our method to tile the child window.
  2250.     *partWindowBounds = TilePartWindow(ev, &bounds, partWindowBounds);
  2251.     
  2252.     // Set the port and origin so we can convert the rect to
  2253.     // global Window Mgr coordinates.
  2254.     SetPort(activeFacet->GetCanvas(ev)->GetQDPort(ev));
  2255.     SetOrigin(0,-kMacWindowTitleBarHeight);
  2256.     
  2257.     // Convert the local coordinates to global Window Mgr coordinates.
  2258.     LocalToGlobal((Point*)(&(partWindowBounds->top)));
  2259.     LocalToGlobal((Point*)(&(partWindowBounds->bottom)));
  2260.     
  2261.     return *partWindowBounds;
  2262. }
  2263.  
  2264. //------------------------------------------------------------------------------
  2265. // Method:        ZoomPartWindow
  2266. // Origin:        SamplePart
  2267. //
  2268. // Description:    This method is called by the part when a frame is being opened
  2269. //                or closed in the case that zooming rectangles should be shown.                
  2270. //------------------------------------------------------------------------------
  2271.  
  2272. void SamplePart::ZoomPartWindow( Environment*        ev,
  2273.                                     ODFrame*            frame,
  2274.                                     ODWindow*            window,
  2275.                                     ODBoolean            openingWindow )
  2276. {
  2277.     SOM_Trace("SamplePart","ZoomPartWindow");
  2278.  
  2279.     const ODSShort kNumZoomSteps = 12;
  2280.  
  2281.     Rect frameRect;
  2282.     {
  2283.         // We need to know which facet of the frame we are opening to position
  2284.         // the child window.
  2285.         ODFacet* zoomFacet = kODNULL;
  2286.         
  2287.         TRY
  2288.             zoomFacet = this->GetActiveFacetForFrame(ev, frame);
  2289.         CATCH_ALL
  2290.         ENDTRY
  2291.         
  2292.         // In case there isn't an active facet for the frame, .
  2293.         if ( zoomFacet == kODNULL )
  2294.         {
  2295.             TempODFrameFacetIterator iter(ev, frame);
  2296.             zoomFacet = iter.First();
  2297.         }
  2298.         
  2299.         if ( zoomFacet != kODNULL )
  2300.         {
  2301.             // For doing the zoom rects, we need the to know the area of the
  2302.             // document the frame occupies. We do this by getting the bouding
  2303.             // box and offsetting it by the aggregate external window transform
  2304.             // of the facet.
  2305.             TempODTransform windowFrameTransform =
  2306.                                 zoomFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2307.             TempODShape boundsShape =
  2308.                                 ODCopyAndRelease(ev, zoomFacet->GetFrame(ev)
  2309.                                                     ->AcquireFrameShape(ev, kODNULL));
  2310.             
  2311.             // Translate the bounds rect into window coordinates.
  2312.             boundsShape->Transform(ev, windowFrameTransform);
  2313.             
  2314.             // Get and convert the bounding box into a QuickDraw rectangle.
  2315.             ODRect bbox;
  2316.             boundsShape->GetBoundingBox(ev, &bbox);
  2317.             FixedToIntRect(bbox, frameRect);
  2318.                 
  2319.             // Set the port and origin so we can convert the rect to
  2320.             // global Window Mgr coordinates.
  2321.             SetPort(zoomFacet->GetCanvas(ev)->GetQDPort(ev));
  2322.             SetOrigin(0, 0);
  2323.             
  2324.             // Convert the local coordinates to global Window Mgr coordinates.
  2325.             LocalToGlobal((Point*) &frameRect.top);
  2326.             LocalToGlobal((Point*) &frameRect.bottom);
  2327.         }
  2328.     }
  2329.     
  2330.     Rect windowRect;
  2331.     {
  2332.         ODPlatformWindow platformWindow = window->GetPlatformWindow(ev);
  2333.  
  2334.         windowRect = platformWindow->portRect;
  2335.         windowRect.top -= kMacWindowTitleBarHeight;
  2336.         
  2337.         // Set the port and origin so we can convert the rect to
  2338.         // global Window Mgr coordinates.
  2339.         SetPort(platformWindow);
  2340.         SetOrigin(0, 0);
  2341.         
  2342.         // Convert the local coordinates to global Window Mgr coordinates.
  2343.         LocalToGlobal((Point*) &windowRect.top);
  2344.         LocalToGlobal((Point*) &windowRect.bottom);
  2345.     }
  2346.     
  2347.     Rect fromRect = openingWindow ? frameRect  : windowRect;
  2348.     Rect toRect   = openingWindow ? windowRect : frameRect;
  2349.     
  2350.     if ( !openingWindow )
  2351.         window->Hide(ev);
  2352.  
  2353.     ZoomRects(&fromRect, &toRect, kNumZoomSteps, 
  2354.                 openingWindow ? zoomAccelerate : zoomDecelerate);
  2355. }
  2356.  
  2357. //------------------------------------------------------------------------------
  2358. // Method:        GetActiveFacetForFrame
  2359. // Origin:        SamplePart
  2360. //
  2361. // Description:    This method is called by the part when it needs to know what the
  2362. //                current active facet is.
  2363. //
  2364. //                The part uses this method specifically to find the facet of a
  2365. //                source frame when opening a part window.
  2366. //------------------------------------------------------------------------------
  2367.  
  2368. ODFacet* SamplePart::GetActiveFacetForFrame( Environment*    ev,
  2369.                                              ODFrame*        frame )
  2370. {
  2371.     SOM_Trace("SamplePart","GetActiveFacetForFrame");
  2372.  
  2373.     ODFacet*    facet = kODNULL;
  2374.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2375.     
  2376.     // If the frame is active, and it should be, get the active facet
  2377.     // from the frame state info.
  2378.     if ( frameInfo->IsFrameActive() )
  2379.     {
  2380.         facet = frameInfo->GetActiveFacet();
  2381.     }
  2382.     else
  2383.     // Otherwise, iterate over the display frames looking for one
  2384.     // that has an active facet... there should be at least one.
  2385.     {
  2386.         TempODFrameFacetIterator fiter(ev, frame);
  2387.         for ( ODFacet* selectedFacet = fiter.First(); fiter.IsNotComplete();
  2388.               selectedFacet = fiter.Next() )
  2389.         {
  2390.             if ( selectedFacet->IsSelected(ev) )
  2391.             {
  2392.                 facet = selectedFacet;
  2393.                 break;
  2394.             }
  2395.         }
  2396.     }
  2397.     
  2398.     // If there are no active facets anywhere, this method should never
  2399.     // have been called, so signal an error.
  2400.     if ( facet == kODNULL )
  2401.         THROW(kODErrInvalidFrame);
  2402.         
  2403.     return facet;
  2404. }
  2405.  
  2406. //==============================================================================
  2407. #pragma mark    • Imaging •
  2408. //==============================================================================
  2409.  
  2410. //------------------------------------------------------------------------------
  2411. // Method:        FacetAdded
  2412. // Origin:        ODPart
  2413. //
  2414. // Description:    This method is called when any part adds a facet to
  2415. //                one of our display frames.
  2416. //------------------------------------------------------------------------------
  2417.  
  2418. void SamplePart::FacetAdded( Environment*    ev,
  2419.                              ODFacet*        facet )
  2420. {
  2421.     SOM_Trace("SamplePart","FacetAdded");
  2422.  
  2423.     ODFrame* frame = facet->GetFrame(ev);
  2424.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2425.         
  2426.     // If a root facet is being added, the frame should be activated when the
  2427.     // window is "selected". This prevents OpenDoc from getting into an
  2428.     // ambiguous state of no part having the selection focus.
  2429.  
  2430.     if ( frame->IsRoot(ev) )
  2431.     {
  2432.         frameInfo->SetActiveFacet(facet);
  2433.         frameInfo->SetFrameReactivate(kODTrue);
  2434.     }
  2435.     
  2436.     // If a frame had all of its facets removed, the frame would have
  2437.     // hidden any of its part windows. If the frame becomes visible again,
  2438.     // by having a facet added to it, we will "show" the part window for
  2439.     // the frame.
  2440.     
  2441.     if ( (CountFramesFacets(ev, frame) == 1) )
  2442.     {
  2443.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2444.         if ( window ) window->Show(ev);
  2445.     }
  2446. }
  2447.  
  2448. //------------------------------------------------------------------------------
  2449. // Method:        FacetRemoved
  2450. // Origin:        ODPart
  2451. //
  2452. // Description:    This method is called when any part removes a facet
  2453. //                from one of our display frames.
  2454. //
  2455. //                The part just removes the "active" note from the
  2456. //                appropriate display frame if necessary since this
  2457. //                facet will not be available, nor active, again.
  2458. //------------------------------------------------------------------------------
  2459.  
  2460. void SamplePart::FacetRemoved( Environment*    ev,
  2461.                                ODFacet*        facet )
  2462. {
  2463.     SOM_Trace("SamplePart","FacetRemoved");
  2464.  
  2465.     ODFrame*    frame = facet->GetFrame(ev);
  2466.     TempODFrame    containingFrame = frame->AcquireContainingFrame(ev);
  2467.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2468.  
  2469.     // If the facet was the active facet, it can no longer be.
  2470.        if ( ODObjectsAreEqual(ev, frameInfo->GetActiveFacet(), facet) )
  2471.         frameInfo->SetActiveFacet(kODNULL);
  2472.  
  2473.     // If a frame has all of its facets removed and its containing frame set
  2474.     // to NULL, the frame becomes "hidden". If the frame owns a part window,
  2475.     // the part window should also be hidden.
  2476.     
  2477.     if ( (CountFramesFacets(ev, frame) == 0) &&
  2478.             (containingFrame == kODNULL) )
  2479.     {
  2480.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2481.         if ( window ) window->Hide(ev);
  2482.     }
  2483. }
  2484.  
  2485. //------------------------------------------------------------------------------
  2486. // Method:        Draw
  2487. // Origin:        ODPart
  2488. //
  2489. // Description:    This method is called when a facet of a part's display
  2490. //                frame intersects the invalidated portion of an OpenDoc
  2491. //                window. The invalidShape parameter passed in is the
  2492. //                portion of the facet which has been invalidated.
  2493. //
  2494. //                The part sets up the drawing environment using a
  2495. //                C++ helper class (CFocus) and then calls the
  2496. //                appropriate drawing method based on the frame's
  2497. //                viewType.
  2498. //------------------------------------------------------------------------------
  2499.  
  2500. void SamplePart::Draw( Environment*        ev,
  2501.                        ODFacet*            facet,
  2502.                        ODShape*            invalidShape )
  2503. {
  2504.     SOM_Trace("SamplePart","Draw");
  2505.  
  2506.     // Focus the port and origin for drawing in our facet.
  2507.     // Note that this instance of the CFocusDrawingEnv class
  2508.     // is being allocated on the stack. When the execution
  2509.     // leaves the scope of this method, the destructor (which
  2510.     // cleans up the drawing environment) is automatically
  2511.     // called.
  2512.     CFocus initiateDrawing(ev, facet, invalidShape);
  2513.     
  2514.     ODTypeToken view = facet->GetFrame(ev)->GetViewType(ev);
  2515.     
  2516.     if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  2517.         this->DrawIconView(ev, facet);
  2518.     else if ( view == gGlobals->fThumbnailView )
  2519.         this->DrawThumbnailView(ev, facet);
  2520.     else
  2521.         this->DrawFrameView(ev, facet);
  2522. }
  2523.  
  2524. //------------------------------------------------------------------------------
  2525. // Method:        DrawFrameView
  2526. // Origin:        SamplePart
  2527. //
  2528. // Description:    This method is called by the part when the frame being drawn is
  2529. //                in "frame" view.
  2530. //
  2531. //                SamplePart really has not intrisic content. However, to provide
  2532. //                some visual display, we draw the class name at 80% of the
  2533. //                frame's current height using an bold font.
  2534. //------------------------------------------------------------------------------
  2535.  
  2536. void SamplePart::DrawFrameView( Environment*    ev,
  2537.                                 ODFacet*        facet )
  2538. {
  2539.     SOM_Trace("SamplePart","DrawFrameView");
  2540.  
  2541.     ODFrame*    frame;
  2542.     ODUShort    frameHeight = 0;
  2543.     ODUShort    frameWidth = 0;
  2544.     RgnHandle    frameRgn;
  2545.     FontInfo    finfo;
  2546.     Str63        defaultString;
  2547.     CFrameInfo*    frameInfo;
  2548.     GrafPtr        port;
  2549.  
  2550.  
  2551.     GetPort(&port);
  2552.     EraseRect(&port->portRect);
  2553.     
  2554.     // If the facet being draw is dependent to a source frame in
  2555.     // another window, we need to access the source frame to determine
  2556.     // what size to draw the content.
  2557.  
  2558.     frameInfo = (CFrameInfo*) facet->GetFrame(ev)->GetPartInfo(ev);
  2559.     if ( frameInfo->HasSourceFrame() )
  2560.         frame = frameInfo->GetSourceFrame(ev);
  2561.     else
  2562.         frame = facet->GetFrame(ev);
  2563.  
  2564.     // Get the facet's canvas so shapes are returned in the correct
  2565.     // coordinate system.
  2566.     ODCanvas* biasCanvas = facet->GetCanvas(ev);
  2567.  
  2568.     // Calculate font height for drawing.
  2569.     TempODShape frameShape = frame->AcquireFrameShape(ev, biasCanvas);
  2570.     frameRgn = frameShape->GetQDRegion(ev);
  2571.     frameHeight = (**frameRgn).rgnBBox.bottom - (**frameRgn).rgnBBox.top;
  2572.     frameWidth = (**frameRgn).rgnBBox.right - (**frameRgn).rgnBBox.left;
  2573.  
  2574.     // Save off port chararcteristics so we can restore it later.
  2575.     ODUShort size = port->txSize;
  2576.     ODUShort font = port->txFont;
  2577.     Style face = port->txFace;
  2578.  
  2579.     // Set the font size to almost fill the frame.
  2580.     TextSize((ODUShort)(frameHeight * 0.8));
  2581.     // Use the default Application font for this script system.
  2582.     TextFont(1);
  2583.     TextFace(bold + condense);
  2584.         
  2585.     GetFontInfo(&finfo);
  2586.     
  2587.     ODSLong rfRef;
  2588.     rfRef = BeginUsingLibraryResources();
  2589.     {
  2590.         PenState penState;
  2591.         GetPenState(&penState);
  2592.         
  2593.         PenNormal();        
  2594.         GetIndString(defaultString, kMenuStringResID, kDefaultContent1ID);
  2595.         MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2),
  2596.                     frameHeight - (finfo.descent - 2));
  2597.         DrawString(defaultString);
  2598.         
  2599.         // If the part is selected, fill the background with
  2600.         // the highlight color.
  2601.         if ( facet->GetHighlight(ev) == kODFullHighlight )
  2602.         {
  2603.             UInt8 mode = LMGetHiliteMode();
  2604.             BitClr(&mode,pHiliteBit);
  2605.             LMSetHiliteMode(mode);
  2606.             InvertRect(&port->portRect);
  2607.         }
  2608.         
  2609.         TextMode(srcXor);
  2610.         TextSize(24);
  2611.         TextFace(bold + extend);
  2612.  
  2613.         GetIndString(defaultString, kMenuStringResID, kDefaultContent2ID);
  2614.         MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2),
  2615.                     (frameHeight / 2) + 6);
  2616.         DrawString(defaultString);
  2617.         
  2618.         SetPenState(&penState);
  2619.     }
  2620.     EndUsingLibraryResources(rfRef);
  2621.  
  2622.     // Restore port chararcteristics.
  2623.     SetPort(port);
  2624.     port->txSize = size;
  2625.     port->txFont = font;
  2626.     port->txFace = face;
  2627. }
  2628.  
  2629. //------------------------------------------------------------------------------
  2630. // Method:        DrawIconView
  2631. // Origin:        SamplePart
  2632. //
  2633. // Description:    This method is called by the part when the frame being
  2634. //                drawn is in "standard icon" view.
  2635. //
  2636. //                The part uses the Icon Utilities toolbox manager to
  2637. //                aid in drawing icons in active windows. The Guidelines
  2638. //                require a different appearance for selected icons in
  2639. //                inactive windows, which we do manually.
  2640. //------------------------------------------------------------------------------
  2641.  
  2642. void SamplePart::DrawIconView( Environment*        ev,
  2643.                                ODFacet*            facet )
  2644. {
  2645.     SOM_Trace("SamplePart","DrawIconView");
  2646.  
  2647.     Rect                iconRect;
  2648.     IconTransformType     transformType = ttNone;
  2649.     CFrameInfo*            frameInfo;
  2650.     ODFrame*            frame; 
  2651.     ODTypeToken            viewType;
  2652.     
  2653.     frame        = facet->GetFrame(ev);
  2654.     viewType    = frame->GetViewType(ev);
  2655.     frameInfo     = (CFrameInfo*) frame->GetPartInfo(ev);
  2656.     
  2657.     // Check to see if the facet is selected
  2658.     if ( facet->GetHighlight(ev) == kODFullHighlight )
  2659.         transformType = ttSelected;
  2660.     
  2661.     // Check to see if the frame has been opened into a part window.
  2662.     TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2663.     if ( window && window->IsShown(ev) )
  2664.         transformType |= ttOpen;
  2665.     
  2666.     // Draw the icon.
  2667.     if ( viewType == gGlobals->fLargeIconView )
  2668.         SetRect(&iconRect, 0, 0, kODLargeIconSize, kODLargeIconSize);
  2669.     else // ( viewType == gGlobals->fSmallIconView )
  2670.         SetRect(&iconRect, 0, 0, kODSmallIconSize, kODSmallIconSize);
  2671.  
  2672.     CUsingLibraryResources res;
  2673.     PlotIconID(&iconRect, atAbsoluteCenter, transformType, kBaseResourceID);
  2674. }
  2675.  
  2676. //------------------------------------------------------------------------------
  2677. // Method:        DrawThumbnailView
  2678. // Origin:        SamplePart
  2679. //
  2680. // Description:    This method is called by the part when the frame being
  2681. //                drawn is in "thumbnail" view.
  2682. //
  2683. //                The part uses a picture for its thumbnail view because
  2684. //                it has no intrinsic content. A picture resource is
  2685. //                probably not sufficient for parts with real content.
  2686. //------------------------------------------------------------------------------
  2687.  
  2688. void SamplePart::DrawThumbnailView( Environment*    ev,
  2689.                                     ODFacet*        facet )
  2690. {
  2691.     SOM_Trace("SamplePart","DrawThumbnailView");
  2692.     
  2693.     // Create or retrieve a cached thumbnail picture.
  2694.     PicHandle thumbnail = this->GenerateThumbnail(ev, facet->GetFrame(ev));
  2695.     
  2696.     Rect bounds = (**thumbnail).picFrame;
  2697.     DrawPicture(thumbnail, &bounds);
  2698. }
  2699.  
  2700. //------------------------------------------------------------------------------
  2701. // Method:        GenerateThumbnail
  2702. // Origin:        SamplePart
  2703. //
  2704. // Description:    This method is called by the part to generate a thumbnail view
  2705. //                from the current content.
  2706. //
  2707. //                The part has no content, so we merely load a picture.
  2708. //------------------------------------------------------------------------------
  2709.  
  2710. PicHandle SamplePart::GenerateThumbnail( Environment*    ev,
  2711.                                          ODFrame*        frame )
  2712. {
  2713.     SOM_Trace("SamplePart","GenerateThumbnail");
  2714.     
  2715.     if ( gGlobals->fThumbnail == kODNULL )
  2716.     {
  2717.         // In cases where a part has been instantiated from scratch and has no
  2718.         // content (yet), it is appropriate to display a PICT or some graphic
  2719.         // in place of a "real" thumbnail.
  2720.         
  2721.         LoadThumbnail(ev, &gGlobals->fThumbnail);
  2722.     
  2723.         // If we were unable to load the PICT resource for whatever reason
  2724.         // we will default back to a "frame" view and throw the Resource
  2725.         // Manager error as an exception.
  2726.         if ( gGlobals->fThumbnail == kODNULL )
  2727.         {
  2728.             frame->ChangeViewType(ev, gGlobals->fFrameView);
  2729.             
  2730.             // There is a bug in ResError, when resources are not found,
  2731.             // which may cause noErr to be returned. If that is the case,
  2732.             // we throw resNotFound.
  2733.             THROW_IF_ERROR((ODError)ResError());
  2734.             THROW(resNotFound);
  2735.         }
  2736.     }
  2737.         
  2738.     return (PicHandle)gGlobals->fThumbnail;
  2739. }
  2740.  
  2741. //------------------------------------------------------------------------------
  2742. // Method:        GeometryChanged
  2743. // Origin:        ODPart
  2744. //
  2745. // Description:    This method is called when the ExternalTransform or
  2746. //                ClipShape of a facet on one this part's display frames
  2747. //                changes.
  2748. //------------------------------------------------------------------------------
  2749.  
  2750. void SamplePart::GeometryChanged( Environment*    ev,
  2751.                                   ODFacet*        facet,
  2752.                                   ODBoolean        clipShapeChanged,
  2753.                                   ODBoolean        /*externalTransformChanged*/ )
  2754. {
  2755.     SOM_Trace("SamplePart","GeometryChanged");
  2756.  
  2757.     if ( clipShapeChanged )
  2758.         // Specifying kODNULL means to invalidate the clipShape (which was
  2759.         // calculated from the usedShape).
  2760.         facet->Invalidate(ev, kODNULL, kODNULL);
  2761. }
  2762.  
  2763. //------------------------------------------------------------------------------
  2764. // Method:        HighlightChanged
  2765. // Origin:        ODPart
  2766. //
  2767. // Description:    This method is called when a facet....
  2768. //------------------------------------------------------------------------------
  2769.  
  2770. void SamplePart::HighlightChanged(Environment* ev, ODFacet* facet)
  2771. {
  2772.     ODFrame* frame = facet->GetFrame(ev);
  2773.     
  2774.     // The frame view has no "special" drawing characteristics
  2775.     // when opened or selected, so we don't need to update our
  2776.     // content.
  2777.     
  2778.     if ( frame->GetViewType(ev) != gGlobals->fFrameView )
  2779.         frame->Invalidate(ev, kODNULL, kODNULL);
  2780. }
  2781.  
  2782. //==============================================================================
  2783. #pragma mark    • Activation •
  2784. //==============================================================================
  2785.  
  2786. //------------------------------------------------------------------------------
  2787. // Method:        BeginRelinquishFocus
  2788. // Origin:        ODPart
  2789. //
  2790. // Description:    This method is called when another part (or possibly
  2791. //                ourself) is requesting a focus for one of its display
  2792. //                frames. Returning true means we are willing to give
  2793. //                up the requested focus.
  2794. //
  2795. //                The part willingly gives up any focus unless it is the
  2796. //                modal focus which we don't want to give up until we
  2797. //                are completely done displaying a modal dialog.
  2798. //------------------------------------------------------------------------------
  2799.  
  2800. ODBoolean SamplePart::BeginRelinquishFocus( Environment*    ev,
  2801.                                             ODTypeToken        focus,
  2802.                                             ODFrame*        /*ownerFrame*/,
  2803.                                             ODFrame*        proposedFrame )
  2804. {
  2805.     SOM_Trace("SamplePart","BeginRelinquishFocus");
  2806.  
  2807.     ODBoolean willRelinquish = kODTrue;
  2808.  
  2809.     // Another part is trying to put up a Modal dialog while we
  2810.     // are currently displaying ours. Deny the request.
  2811.     if ( focus == gGlobals->fModalFocus )
  2812.     {
  2813.         TempODPart proposedPart = ODAcquirePart(ev,proposedFrame);
  2814.         if ( ODObjectsAreEqual(ev, proposedPart, fSelf) == kODFalse )
  2815.             willRelinquish = kODFalse;
  2816.     }
  2817.                 
  2818.     return willRelinquish;
  2819. }
  2820.  
  2821. //------------------------------------------------------------------------------
  2822. // Method:        CommitRelinquishFocus
  2823. // Origin:        ODPart
  2824. //
  2825. // Description:    This method is called when it is actually time to give
  2826. //                up a focus that had been requested by another part (or
  2827. //                possibly ourself).
  2828. //
  2829. //                The part calls its FocusLost method to handle the 
  2830. //                "reliquishing" of the particular focus.
  2831. //------------------------------------------------------------------------------
  2832.  
  2833. void SamplePart::CommitRelinquishFocus( Environment*    ev,
  2834.                                         ODTypeToken        focus,
  2835.                                         ODFrame*        ownerFrame,
  2836.                                         ODFrame*        /*proposedFrame*/ )
  2837. {
  2838.     SOM_Trace("SamplePart","CommitRelinquishFocus");
  2839.  
  2840.     // We agreed to give up our FocusSet and now we are being asked to
  2841.     // do so.
  2842.     this->FocusLost(ev, focus, ownerFrame);
  2843. }
  2844.  
  2845. //------------------------------------------------------------------------------
  2846. // Method:        AbortRelinquishFocus
  2847. // Origin:        ODPart
  2848. //
  2849. // Description:    This method is called when another part (or possibly
  2850. //                ourself) requested a focus for one of its display
  2851. //                frames, but we returned kODFalse from
  2852. //                BeginRelinqishFocus for one, or all, of the requested
  2853. //                focus. At this point, we are being told to resume
  2854. //                ownership of the focus.
  2855. //------------------------------------------------------------------------------
  2856.  
  2857. void SamplePart::AbortRelinquishFocus( Environment*        ev,
  2858.                                        ODTypeToken        /*focus*/,
  2859.                                        ODFrame*            /*ownerFrame*/,
  2860.                                        ODFrame*            /*proposedFrame*/ )
  2861. {
  2862.     SOM_Trace("SamplePart","AbortRelinquishFocus");
  2863.  
  2864.     // Some parts may have suspended some events in the BeginRelinquishFocus
  2865.     // method. If so, they would resume those events here.
  2866. }
  2867.  
  2868. //------------------------------------------------------------------------------
  2869. // Method:        FocusAcquired
  2870. // Origin:        ODPart
  2871. //
  2872. // Description:    This method is called when the Arbitrator has
  2873. //                registered us as the "owner" of the particular focus.
  2874. //                This can occur if we are explicitly assigned a focus, or if a
  2875. //                focus is transfered to one of the part's display frames.
  2876. //
  2877. //                The part will request its complete focus set to become "active".
  2878. //                If the part is successful, we notify ourself to become active.
  2879. //------------------------------------------------------------------------------
  2880.  
  2881. void SamplePart::FocusAcquired( Environment*    ev,
  2882.                                 ODTypeToken        focus,
  2883.                                 ODFrame*        ownerFrame )
  2884. {
  2885.     SOM_Trace("SamplePart","FocusAcquired");
  2886.  
  2887.     ODArbitrator* arbitrator =  ODGetSession(ev,fSelf)->GetArbitrator(ev);
  2888.  
  2889.     if ( arbitrator->RequestFocusSet(ev, gGlobals->fUIFocusSet, ownerFrame) )
  2890.     {
  2891.         this->PartActivated(ev, ownerFrame);
  2892.     }
  2893. }
  2894.  
  2895. //------------------------------------------------------------------------------
  2896. // Method:        FocusLost
  2897. // Origin:        ODPart
  2898. //
  2899. // Description:    This method is called when the Arbitrator has
  2900. //                unregistered us as the "owner" of the particular
  2901. //                focus.
  2902. //
  2903. //                The part unmarks the active frame if the selection
  2904. //                focus is lost.
  2905. //------------------------------------------------------------------------------
  2906.  
  2907. void SamplePart::FocusLost( Environment*    ev,
  2908.                             ODTypeToken        focus,
  2909.                             ODFrame*        ownerFrame )
  2910. {
  2911.     SOM_Trace("SamplePart","FocusLost");
  2912.  
  2913.     if ( focus == gGlobals->fSelectionFocus )
  2914.     {
  2915.         CFrameInfo* frameInfo = (CFrameInfo*) ownerFrame->GetPartInfo(ev);
  2916.         frameInfo->SetFrameActive(kODFalse);
  2917.     }
  2918. }
  2919.  
  2920. //------------------------------------------------------------------------------
  2921. // Method:        RelinquishAllFoci
  2922. // Origin:        SamplePart
  2923. //
  2924. // Description:    This method is called when a frame is going away. The method
  2925. //                relinquishes all foci the frame owns.
  2926. //------------------------------------------------------------------------------
  2927.  
  2928. void SamplePart::RelinquishAllFoci( Environment*    ev,
  2929.                                     ODFrame*        frame )
  2930. {
  2931.     SOM_Trace("SamplePart","RelinquishAllFoci");
  2932.  
  2933.     ODArbitrator* arbitrator = ODGetSession(ev,fSelf)->GetArbitrator(ev);
  2934.     
  2935.     TRY
  2936.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fSelectionFocus);
  2937.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  2938.         {
  2939.             arbitrator->RelinquishFocus(ev, gGlobals->fSelectionFocus, frame);
  2940.             this->FocusLost(ev, gGlobals->fSelectionFocus, frame);
  2941.         }
  2942.     CATCH_ALL
  2943.     ENDTRY
  2944.  
  2945.     TRY
  2946.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fMenuFocus);
  2947.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  2948.         {
  2949.             arbitrator->RelinquishFocus(ev, gGlobals->fMenuFocus, frame);
  2950.             this->FocusLost(ev, gGlobals->fMenuFocus, frame);
  2951.         }
  2952.     CATCH_ALL
  2953.     ENDTRY
  2954. }
  2955.  
  2956. //------------------------------------------------------------------------------
  2957. // Method:        PartActivated
  2958. // Origin:        SamplePart
  2959. //
  2960. // Description:    This method is called when the part has successfully acquired
  2961. //                the set of foci which allow it to "run".
  2962. //------------------------------------------------------------------------------
  2963.  
  2964. void SamplePart::PartActivated( Environment*    ev,
  2965.                                 ODFrame*        frame )
  2966. {
  2967.     SOM_Trace("SamplePart","PartActivated");
  2968.     
  2969.     // We are required to re-validate the menubar before displaying it because
  2970.     // any part can/could swap the base menubar at any time.
  2971.     if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  2972.     {
  2973.         ODReleaseObject(ev, gGlobals->fMenuBar);
  2974.         gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  2975.         
  2976.         // After copying the "new" base menu bar, don't forget to re-install
  2977.         // your part's menus.
  2978.     }
  2979.         
  2980.     // Display our menu bar.
  2981.     gGlobals->fMenuBar->Display(ev);
  2982.     
  2983.     // And set our "active" state.
  2984.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2985.     frameInfo->SetFrameActive(kODTrue);
  2986. }
  2987.  
  2988. //------------------------------------------------------------------------------
  2989. // Method:        ActivateFrame
  2990. // Origin:        SamplePart
  2991. //
  2992. // Description:    This method is called by the part when a kODEvtMouseUp
  2993. //                occurs in an inactive frame in an active window, and
  2994. //                when an OpenDoc document comes forward.
  2995. //
  2996. //                The part activates the frame by requesting the
  2997. //                UIFocusSet (created in Initialize) and by calling
  2998. //                FocusAcquired if we were successful. The method
  2999. //                returns true if no problems were encountered as a
  3000. //                signal to the caller that the frame is now "active".
  3001. //------------------------------------------------------------------------------
  3002.  
  3003. ODBoolean SamplePart::ActivateFrame( Environment*    ev,
  3004.                                      ODFrame*        frame )
  3005. {
  3006.     SOM_Trace("SamplePart","ActivateFrame");
  3007.  
  3008.     ODBoolean activated = kODFalse;
  3009.  
  3010.     // Request the set of foci necessary to become active.
  3011.     if ( ODGetSession(ev,fSelf)->GetArbitrator(ev)
  3012.             ->RequestFocusSet(ev, gGlobals->fUIFocusSet, frame) )
  3013.     {
  3014.         // Activate the part.
  3015.         this->PartActivated(ev, frame);
  3016.         // We were able to become active.
  3017.         activated = kODTrue;
  3018.     }
  3019.     
  3020.     // Let our caller know we succeded or failed.
  3021.     return activated;
  3022. }
  3023.  
  3024. //------------------------------------------------------------------------------
  3025. // Method:        WindowActivating
  3026. // Origin:        SamplePart
  3027. //
  3028. // Description:    This method is called by the part when a window activation
  3029. //                event (kODEvtActivate) occurs.
  3030. //
  3031. //                The part remembers the frame's active state and restores it when
  3032. //                events come in. If the frame is active and the window is being
  3033. //                sent into the background, remember to reactivate the part when
  3034. //                the window is reactivated.
  3035. //------------------------------------------------------------------------------
  3036.  
  3037. void SamplePart::WindowActivating( Environment*        ev,
  3038.                                    ODFrame*            frame,
  3039.                                    ODBoolean        activating )
  3040. {
  3041.     SOM_Trace("SamplePart","WindowActivating");
  3042.  
  3043.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3044.     
  3045.     // The window is being activated and we had the selection focus when
  3046.     // the window was deactivated, so activate ourself.
  3047.     if ( activating && frameInfo->FrameNeedsReactivating() )
  3048.     {
  3049.         this->ActivateFrame(ev, frame);
  3050.         frameInfo->SetFrameReactivate(kODFalse);
  3051.     }
  3052.     // The window is being deactivated and we are the active part.
  3053.     // Give up our foci and remind ourselves that we need to request
  3054.     // the focus when the window is reactivated.
  3055.     else if ( !activating && frameInfo->IsFrameActive() )
  3056.     {
  3057.         frameInfo->SetFrameReactivate(kODTrue);
  3058.     }
  3059. }
  3060.  
  3061. //==============================================================================
  3062. #pragma mark    • Event Handling •
  3063. //==============================================================================
  3064.  
  3065. //------------------------------------------------------------------------------
  3066. // Method:        HandleEvent
  3067. // Origin:        ODPart
  3068. //
  3069. // Description:    The method is called when an event, which falls into
  3070. //                the category of an owned focus, occurs. The two
  3071. //                exceptions to this are "mouse movement" events and 
  3072. //                embedded frame events, which can occur when a part
  3073. //                owns no foci.
  3074. //
  3075. //                The part returns true if the event was handled.
  3076. //------------------------------------------------------------------------------
  3077.  
  3078.  
  3079. ODBoolean SamplePart::HandleEvent( Environment*        ev,
  3080.                                    ODEventData*        event,
  3081.                                    ODFrame*            frame,
  3082.                                    ODFacet*            facet,
  3083.                                    ODEventInfo*        eventInfo )
  3084. {
  3085.     SOM_Trace("SamplePart","HandleEvent");
  3086.  
  3087.     ODBoolean    eventHandled = kODFalse;
  3088.  
  3089.     // Event handling is basically the same as standard Macintosh applications,
  3090.     // except that the events have been renamed for cross-platform compatability.
  3091.     
  3092.     switch ( event->what )
  3093.     {
  3094.         case kODEvtMouseDown:
  3095.         case kODEvtMouseUp:
  3096.             eventHandled = this->HandleMouseEvent(ev, event, facet, eventInfo);
  3097.             break;
  3098.             
  3099.         case kODEvtMenu:
  3100.             eventHandled = this->HandleMenuEvent(ev, event, frame);
  3101.             break;
  3102.  
  3103.         case kODEvtActivate:
  3104.             // We are being notified that a window we are displayed in has
  3105.             // just been de/activated (un/hilighted).
  3106.             this->WindowActivating(ev, frame, (event->modifiers & activeFlag));
  3107.             eventHandled = kODTrue;
  3108.             break;
  3109.     
  3110.         case kODEvtMouseEnter:
  3111.         case kODEvtMouseLeave:
  3112.             SetCursor(&ODQDGlobals.arrow);
  3113.             eventHandled = kODTrue;
  3114.             break;
  3115.  
  3116.         case kODEvtMouseWithin:
  3117.             eventHandled = kODTrue;
  3118.             break;
  3119.  
  3120.         // Other events a part might handle
  3121.         case kODEvtNull:
  3122.         case kODEvtMouseDownEmbedded:
  3123.         case kODEvtMouseUpEmbedded:
  3124.         case kODEvtMouseDownBorder:
  3125.         case kODEvtMouseUpBorder:
  3126.         case kODEvtWindow:
  3127.         case kODEvtKeyDown:
  3128.         case kODEvtKeyUp:
  3129.         case kODEvtAutoKey:
  3130.         case kODEvtOS:
  3131.         case kODEvtDisk:
  3132.         
  3133.         default:
  3134.             break;
  3135.     }
  3136.  
  3137.     return eventHandled;
  3138. }
  3139.  
  3140. //------------------------------------------------------------------------------
  3141. // Method:        AdjustMenus
  3142. // Origin:        ODPart
  3143. //
  3144. // Description:    This method is called when a kODEvtMouseDown event occurs in the
  3145. //                menubar and the part owns the "menu" focus, or when the part is
  3146. //                root part of a document.
  3147. //
  3148. //                The part first verifies that the base menubar has not been
  3149. //                modified, then enables the menu items and changes their names
  3150. //                where appropriate (eg. About SamplePart...).
  3151. //------------------------------------------------------------------------------
  3152.  
  3153. void SamplePart::AdjustMenus( Environment*    ev,
  3154.                               ODFrame*        frame )
  3155. {
  3156.     SOM_Trace("SamplePart","AdjustMenus");
  3157.  
  3158.     // The menubar object always calls the root part's AdjustMenus method before
  3159.     // calling the menu focus owner's. Because of this, we need to validate the
  3160.     // menubar in the case where we are the root part.
  3161.     if ( frame->IsRoot(ev) )
  3162.     {
  3163.         // We are required to re-validate the menubar before displaying it because
  3164.         // any part can/could swap the base menubar at any time.
  3165.         if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  3166.         {
  3167.             ODReleaseObject(ev, gGlobals->fMenuBar);
  3168.             gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  3169.             
  3170.             // After copying the "new" base menu bar, don't forget to re-install
  3171.             // your part's menus.
  3172.         }
  3173.     }        
  3174.  
  3175.     // Enable the "View As Window" command always.
  3176.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandViewAsWin, !frame->IsRoot(ev));
  3177.     
  3178.     TRY
  3179.         ODArbitrator* arbitrator = ODGetSession(ev,fSelf)->GetArbitrator(ev);
  3180.         TempODFrame menuOwner = arbitrator->AcquireFocusOwner(ev, gGlobals->fMenuFocus);
  3181.     
  3182.         // There is no need to load a resource, create an ODIText object, set the menubar,
  3183.         // and cleanup, if we don't own the menu focus.
  3184.         if ( ODObjectsAreEqual(ev, frame, menuOwner) )
  3185.         {
  3186.             Str63 text;
  3187.             
  3188.             // Get the "about" string from our library's resources.
  3189.             // (note: ODGetIndString focuses the resource fork for us)
  3190.             ODGetIndString(text, kMenuStringResID, kAboutTextID);
  3191.             // Create an IText object to pass into the menubar.
  3192.             TempODIText    menuItem(CreateIText(gGlobals->fEditorsScript, gGlobals->fEditorsLanguage,
  3193.                                     (StringPtr)&text));
  3194.             // Change the "About" menu item text for our part.
  3195.             gGlobals->fMenuBar->SetItemString(ev, kODCommandAbout, menuItem);
  3196.         }
  3197.     CATCH_ALL
  3198.         // consume exception
  3199.     ENDTRY
  3200. }
  3201.  
  3202. //------------------------------------------------------------------------------
  3203. // Method:        HandleMenuEvent
  3204. // Origin:        SamplePart
  3205. //
  3206. // Description:    This method is called by the part when a menu event is
  3207. //                received.
  3208. //
  3209. //                Using the menu bar object, we determine what the menu
  3210. //                command is, and call the appropriate method to handle
  3211. //                it.
  3212. //------------------------------------------------------------------------------
  3213.  
  3214. ODBoolean SamplePart::HandleMenuEvent( Environment*        ev,
  3215.                                        ODEventData*        event,
  3216.                                        ODFrame*            frame )
  3217. {
  3218.     SOM_Trace("SamplePart","HandleMenuEvent");
  3219.  
  3220.     ODULong        menuResult    = event->message;
  3221.     ODUShort    menu        = HiWord(menuResult);
  3222.     ODUShort    item        = LoWord(menuResult);
  3223.  
  3224.     switch ( gGlobals->fMenuBar->GetCommand(ev, menu, item) )
  3225.     {
  3226.         case kODCommandAbout:    
  3227.             this->DoDialogBox(ev, frame, kAboutBoxID);
  3228.             break;
  3229.  
  3230.         case kODCommandViewAsWin:
  3231.             this->Open(ev, frame);
  3232.             break;
  3233.  
  3234.         // Other commands a part might handle
  3235.         case kODCommandOpen:
  3236.         case kODCommandInsert:
  3237.         case kODCommandPageSetup:
  3238.         case kODCommandPrint:
  3239.         case kODCommandUndo:
  3240.         case kODCommandRedo:
  3241.         case kODCommandCut:
  3242.         case kODCommandCopy:
  3243.         case kODCommandPaste:
  3244.         case kODCommandPasteAs:
  3245.         case kODCommandClear:
  3246.         case kODCommandSelectAll:
  3247.         case kODCommandGetPartInfo:
  3248.         case kODCommandPreferences:
  3249.  
  3250.         default:
  3251.             return kODFalse;
  3252.     }
  3253.         
  3254.     return kODTrue;
  3255. }
  3256.  
  3257. //------------------------------------------------------------------------------
  3258. // Method:        HandleMouseEvent
  3259. // Origin:        SamplePart
  3260. //
  3261. // Description:    This method is called by the part when a mouse event
  3262. //                is recieved.
  3263. //
  3264. //                A typical part would determine the event type(up/down)
  3265. //                and respond appropriately, but we have no "real"
  3266. //                content model, so we activate the part as appropriate
  3267. //                and call a generic method to handle the event.
  3268. //
  3269. // Remember:    When a frame is inactive, the first mouse up event
  3270. //                should activate it; inactive frames do not recieve
  3271. //                kODEvtMouseDown events.
  3272. //------------------------------------------------------------------------------
  3273.  
  3274. ODBoolean SamplePart::HandleMouseEvent( Environment*    ev,
  3275.                                         ODEventData*    event,
  3276.                                         ODFacet*        facet,
  3277.                                         ODEventInfo*    eventInfo )
  3278. {
  3279.     SOM_Trace("SamplePart","HandleMouseEvent");
  3280.  
  3281.     // If the facet parameter is invalid, the mouse up occurred outside the
  3282.     // bounds of a Modal window, otherwise it should be treated normally.
  3283.     
  3284.     if ( facet != kODNULL )
  3285.     {
  3286.         if ( event->what == kODEvtMouseUp )
  3287.         {
  3288.             ODWindow* window = facet->GetWindow(ev);
  3289.  
  3290.             TRY
  3291.                 // Activate inactive windows on the first mouse up event.
  3292.                 if ( !window->IsActive(ev) )
  3293.                     window->Select(ev);
  3294.                 // Activate the frame (if needed) on all subsequent mouse up events.
  3295.                 else
  3296.                 {
  3297.                     ODFrame* frame = facet->GetFrame(ev);
  3298.                     
  3299.                     // Get our state information from the PartInfo of the frame.
  3300.                     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3301.                                     
  3302.                     // If this frame is not the active one, activate it by requesting
  3303.                     // the appropriate foci.
  3304.         
  3305.                     if ( !frameInfo->IsFrameActive() )
  3306.                     {
  3307.                         if ( this->ActivateFrame(ev, frame) )
  3308.                             // Keep track of which facet was the last active for positioning
  3309.                             // child windows.
  3310.                             frameInfo->SetActiveFacet(facet);
  3311.                         else
  3312.                             // We were unable to acquire the necessary focus and activate it.
  3313.                             return kODFalse;
  3314.                     }
  3315.                 }
  3316.             CATCH_ALL
  3317.             ENDTRY
  3318.         }
  3319.         else if ( event->what == kODEvtMouseDown )                
  3320.         {
  3321.             Point where;
  3322.  
  3323.             // Get the localized mouse coordinates from the Event Info.
  3324.             where.h = FixedToInt(eventInfo->where.x);
  3325.             where.v = FixedToInt(eventInfo->where.y);
  3326.         
  3327.             // Handle the mouse down event.
  3328.             this->DoMouseEvent(ev, facet, &where);
  3329.         }
  3330.     }
  3331.     else
  3332.     {
  3333.         // User clicked outside the bounds of a Modal window, though we actually
  3334.         // never display one.
  3335.         
  3336.         SysBeep(1);
  3337.     }
  3338.  
  3339.     return kODTrue;
  3340. }
  3341.  
  3342. //------------------------------------------------------------------------------
  3343. // Method:        DoMouseEvent
  3344. // Origin:        SamplePart
  3345. //
  3346. // Description:    This method is called by the part to handle mouse
  3347. //                events.
  3348. //------------------------------------------------------------------------------
  3349.  
  3350. void SamplePart::DoMouseEvent( Environment*        ev,
  3351.                                ODFacet*            /*facet*/,
  3352.                                Point*            /*where*/ )
  3353. {
  3354.     SOM_Trace("SamplePart","DoMouseEvent");
  3355.     
  3356.     // If you part allows selections or a lasso tool, this is where you
  3357.     // would handle those events. This is also where you would handle
  3358.     // program controlled buttons or controls.
  3359. }
  3360.  
  3361. //------------------------------------------------------------------------------
  3362. // Method:        DoDialogBox
  3363. // Origin:        SamplePart
  3364. //
  3365. // Description:    This method is called by the part when a dialog needs to be
  3366. //                displayed (eg. the About Box). If a valid error number is passed
  3367. //                in, an error dialog will be displayed.
  3368. //------------------------------------------------------------------------------
  3369.  
  3370. void SamplePart::DoDialogBox( Environment*    ev,
  3371.                               ODFrame*        frame,
  3372.                               ODSShort        dialogID,
  3373.                               ODUShort        errorNumber )
  3374. {
  3375.     SOM_Trace("SamplePart","DoDialogBox");
  3376.  
  3377.     ODFrame* focusFrame = frame;
  3378.     ODSession*    session = ODGetSession(ev,fSelf);
  3379.     
  3380.     // If the calling method does not have a frame available to it, we need to
  3381.     // locate a frame to use for requesting the modal focus. Find the first valid
  3382.     // frame in our display frames list.
  3383.     if ( focusFrame == kODNULL )
  3384.     {
  3385.         CListIterator fiter(fDisplayFrames);
  3386.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  3387.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  3388.         {
  3389.             if ( proxy->FrameIsLoaded(ev) )
  3390.                 focusFrame = proxy->GetFrame(ev);
  3391.             if ( focusFrame ) break;
  3392.         }
  3393.     }
  3394.     
  3395.     // Our dialog boxes are modal so we must request the Modal focus to prevent
  3396.     // multiple modal dialogs being displayed simultaneously.
  3397.     
  3398.     if ( session->GetArbitrator(ev)->RequestFocus(ev, gGlobals->fModalFocus, focusFrame) )
  3399.     {
  3400.         DialogPtr    dialog;
  3401.         ODSShort    itemHit;
  3402.  
  3403.         // Dim the frontmost document window.
  3404.         session->GetWindowState(ev)->DeactivateFrontWindows(ev);
  3405.                 
  3406.         ODSLong rfRef;
  3407.         rfRef = BeginUsingLibraryResources();
  3408.         {            
  3409.             dialog = GetNewDialog(dialogID, kODNULL, (WindowPtr) -1L);
  3410.             
  3411.             if ( dialog )
  3412.             {
  3413.                 if ( errorNumber > 0 )
  3414.                 {
  3415.                     Handle    itemHandle;
  3416.                     Rect    itemRect;
  3417.                     short    itemType;
  3418.                     Str255    errStr;
  3419.                     
  3420.                     GetIndString(errStr, kErrorStringResID, errorNumber);
  3421.                     GetDialogItem(dialog, kErrStrFieldID, &itemType, &itemHandle, &itemRect);
  3422.                     SetDialogItemText(itemHandle, errStr);
  3423.                     
  3424.                     // We don't need the cancel button for an error dialog.
  3425.                     HideDialogItem(dialog, cancel);
  3426.  
  3427.                     SetDialogDefaultItem(dialog, ok);
  3428.                 }
  3429.                 
  3430.                 SetCursor(&ODQDGlobals.arrow);
  3431.                 ShowWindow(dialog);
  3432.                 ModalDialog(kODNULL, &itemHit);
  3433.                 DisposeDialog(dialog);
  3434.             }
  3435.             else
  3436.             {
  3437.                 // Could not load About box dialog... something is amiss.
  3438.                 SysBeep(2);
  3439.             }
  3440.         }
  3441.         EndUsingLibraryResources(rfRef);
  3442.         
  3443.         // Inform the Arbitrator that we no longer require the Modal focus.
  3444.         session->GetArbitrator(ev)->RelinquishFocus(ev, gGlobals->fModalFocus, focusFrame);
  3445.         
  3446.         // Hilite the frontmost document window.
  3447.         session->GetWindowState(ev)->ActivateFrontWindows(ev);
  3448.     }
  3449.     else
  3450.         // If we can't get the modal focus, then another modal dialog is
  3451.         // already being displayed.
  3452.         SysBeep(2);
  3453. }
  3454.  
  3455.